From b8c7a1150fc3b4754fdd873fc4a94ea6cee23697 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Tue, 8 Oct 2024 01:20:42 -0700 Subject: [PATCH 01/47] Kondo 2.0 --- .../src/main/kotlin/KondoKit/Helpers.kt | 170 +++++++- .../src/main/kotlin/KondoKit/HiscoresView.kt | 110 ++++-- .../src/main/kotlin/KondoKit/ImageCanvas.kt | 13 +- .../src/main/kotlin/KondoKit/KondoKitUtils.kt | 100 ----- .../main/kotlin/KondoKit/LootTrackerView.kt | 264 +++++++++++-- .../src/main/kotlin/KondoKit/ProgressBar.kt | 42 +- .../kotlin/KondoKit/ReflectiveEditorView.kt | 315 ++++++++++----- .../main/kotlin/KondoKit/ScrollablePanel.kt | 154 ++++++++ .../src/main/kotlin/KondoKit/XPTrackerView.kt | 207 +++++++--- .../src/main/kotlin/KondoKit/plugin.kt | 362 ++++++++++++------ .../main/kotlin/KondoKit/plugin.properties | 2 +- .../KondoKit/{ => res}/item_configs.json | 0 .../KondoKit/{ => res}/npc_hitpoints_map.json | 0 .../kotlin/KondoKit/res/runescape_small.ttf | Bin 0 -> 33260 bytes 14 files changed, 1265 insertions(+), 474 deletions(-) delete mode 100644 plugin-playground/src/main/kotlin/KondoKit/KondoKitUtils.kt create mode 100644 plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt rename plugin-playground/src/main/kotlin/KondoKit/{ => res}/item_configs.json (100%) rename plugin-playground/src/main/kotlin/KondoKit/{ => res}/npc_hitpoints_map.json (100%) create mode 100644 plugin-playground/src/main/kotlin/KondoKit/res/runescape_small.ttf diff --git a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt index a606805..066edd1 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt @@ -1,10 +1,165 @@ package KondoKit -import java.awt.Color -import java.awt.Dimension -import javax.swing.JPanel +import rt4.GameShell +import java.awt.* +import java.awt.event.MouseListener +import java.lang.reflect.Field +import java.lang.reflect.ParameterizedType +import java.lang.reflect.Type +import java.util.* +import java.util.Timer +import javax.swing.* object Helpers { + + fun convertValue(type: Class<*>, genericType: Type?, value: String): Any { + return when { + type == Int::class.java -> value.toInt() + type == Double::class.java -> value.toDouble() + type == Boolean::class.java -> value.toBoolean() + type == Color::class.java -> convertToColor(value) + type == List::class.java && genericType is ParameterizedType -> { + val actualTypeArgument = genericType.actualTypeArguments.firstOrNull() + when { + value.isBlank() -> emptyList() // Handle empty string by returning an empty list + actualTypeArgument == Int::class.javaObjectType -> value.trim('[', ']').split(",").filter { it.isNotBlank() }.map { it.trim().toInt() } + actualTypeArgument == String::class.java -> value.trim('[', ']').split(",").filter { it.isNotBlank() }.map { it.trim() } + else -> throw IllegalArgumentException("Unsupported List type: $actualTypeArgument") + } + } + else -> value // Default to String + } + } + + fun showToast( + parentComponent: Component?, + message: String, + messageType: Int = JOptionPane.INFORMATION_MESSAGE + ) { + SwingUtilities.invokeLater { + val toast = JWindow() + toast.type = Window.Type.POPUP + toast.background = Color(0, 0, 0, 0) + + val panel = JPanel() + panel.isOpaque = false + panel.layout = BoxLayout(panel, BoxLayout.Y_AXIS) + + val label = JLabel(message) + label.foreground = Color.WHITE + + label.background = when (messageType) { + JOptionPane.ERROR_MESSAGE -> Color(220, 20, 60, 230) // Crimson for errors + JOptionPane.INFORMATION_MESSAGE -> Color(0, 128, 0, 230) // Green for success + JOptionPane.WARNING_MESSAGE -> Color(255, 165, 0, 230) // Orange for warnings + else -> Color(0, 0, 0, 170) // Default semi-transparent black + } + + label.isOpaque = true + label.border = BorderFactory.createEmptyBorder(10, 20, 10, 20) + label.maximumSize = Dimension(242, 50) + label.preferredSize = Dimension(242, 50) + panel.add(label) + + + + toast.contentPane.add(panel) + toast.pack() + + + // Adjust for parent component location if it exists + if (parentComponent != null) { + val parentLocation = parentComponent.locationOnScreen + val x = parentLocation.x + val y = GameShell.canvas.locationOnScreen.y + toast.setLocation(x, y) + } else { + // Fallback to screen center if no parent is provided + val screenSize = Toolkit.getDefaultToolkit().screenSize + val x = (screenSize.width - toast.width) / 2 + val y = screenSize.height - toast.height - 50 + toast.setLocation(x, y) + } + + toast.isVisible = true + + Timer().schedule(object : TimerTask() { + override fun run() { + SwingUtilities.invokeLater { + toast.isVisible = false + toast.dispose() + } + } + }, 2000) + } + } + + + + fun convertToColor(value: String): Color { + val color = Color.decode(value) // Assumes value is in format "#RRGGBB" or "0xRRGGBB" + return color + } + + fun colorToHex(color: Color): String { + return "#%02x%02x%02x".format(color.red, color.green, color.blue) + } + + fun colorToIntArray(color: Color): IntArray { + return intArrayOf(color.red, color.green, color.blue) + } + + interface FieldObserver { + fun onFieldChange(field: Field, newValue: Any?) + } + + fun addMouseListenerToAll(container: Container, listener: MouseListener) { + // Recursively go through all components within the container + for (component in container.components) { + // Add the passed MouseListener to the component + if (component is JComponent || component is Canvas) { + component.addMouseListener(listener) + } + + // If the component is a container, recursively call this function + if (component is Container) { + addMouseListenerToAll(component, listener) + } + } + } + + + + + class FieldNotifier(private val plugin: Any) { + private val observers = mutableListOf() + + fun addObserver(observer: FieldObserver) { + observers.add(observer) + } + + fun notifyFieldChange(field: Field, newValue: Any?) { + for (observer in observers) { + observer.onFieldChange(field, newValue) + } + } + + fun setFieldValue(field: Field, value: Any?) { + field.isAccessible = true + field.set(plugin, value) + notifyFieldChange(field, value) + + try { + val onUpdateMethod = plugin::class.java.getMethod("OnKondoValueUpdated") + onUpdateMethod.invoke(plugin) + } catch (e: NoSuchMethodException) { + // The method doesn't exist + } catch (e: Exception) { + e.printStackTrace() + } + } + } + fun getSpriteId(skillId: Int) : Int { return when (skillId) { 0 -> 197 @@ -78,13 +233,4 @@ object Helpers { else -> Color(128, 128, 128) // Default grey for unhandled skill IDs } } - - class Spacer(width: Int = 0, height: Int = 0) : JPanel() { - init { - preferredSize = Dimension(width, height) - maximumSize = preferredSize - minimumSize = preferredSize - isOpaque = false - } - } } \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt index e1e0f77..3ceb86d 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt @@ -1,9 +1,16 @@ package KondoKit import KondoKit.Constants.COLOR_BACKGROUND_DARK +import KondoKit.Constants.SKILL_DISPLAY_ORDER +import KondoKit.Constants.SKILL_SPRITE_DIMENSION +import KondoKit.Helpers.formatHtmlLabelText import KondoKit.Helpers.getSpriteId +import KondoKit.Helpers.showToast import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR +import KondoKit.plugin.Companion.WIDGET_COLOR +import KondoKit.plugin.Companion.primaryColor +import KondoKit.plugin.Companion.secondaryColor import com.google.gson.Gson import plugin.api.API import rt4.Sprites @@ -16,6 +23,7 @@ import java.awt.event.MouseEvent import java.io.BufferedReader import java.io.InputStreamReader import java.net.HttpURLConnection +import java.net.SocketTimeoutException import java.net.URL import javax.swing.* import javax.swing.border.MatteBorder @@ -28,35 +36,38 @@ object Constants { const val LVL_BAR_SPRITE = 898 // Dimensions - val SEARCH_FIELD_DIMENSION = Dimension(270, 30) + val SEARCH_FIELD_DIMENSION = Dimension(230, 30) val ICON_DIMENSION_SMALL = Dimension(12, 12) val ICON_DIMENSION_MEDIUM = Dimension(18, 20) val ICON_DIMENSION_LARGE = Dimension(30, 30) - val HISCORE_PANEL_DIMENSION = Dimension(270, 400) - val FILTER_PANEL_DIMENSION = Dimension(270, 30) - val SKILLS_PANEL_DIMENSION = Dimension(300, 300) - val TOTAL_COMBAT_PANEL_DIMENSION = Dimension(270, 30) - val SKILL_PANEL_DIMENSION = Dimension(90, 35) + val HISCORE_PANEL_DIMENSION = Dimension(230, 500) + val FILTER_PANEL_DIMENSION = Dimension(230, 30) + val SKILLS_PANEL_DIMENSION = Dimension(230, 290) + val TOTAL_COMBAT_PANEL_DIMENSION = Dimension(230, 30) + val SKILL_PANEL_DIMENSION = Dimension(76, 35) val IMAGE_CANVAS_DIMENSION = Dimension(20, 20) - val NUMBER_LABEL_DIMENSION = Dimension(30, 20) + val SKILL_SPRITE_DIMENSION = Dimension(14, 14) + val NUMBER_LABEL_DIMENSION = Dimension(20, 20) // Colors val COLOR_BACKGROUND_DARK = Color(27, 27, 27) - val COLOR_BACKGROUND_MEDIUM = Color(37, 37, 37) - val COLOR_BACKGROUND_LIGHT = Color(43, 43, 43) + val COLOR_BACKGROUND_MEDIUM = VIEW_BACKGROUND_COLOR val COLOR_FOREGROUND_LIGHT = Color(200, 200, 200) val COLOR_RED = Color.RED val COLOR_SKILL_PANEL = Color(60, 60, 60) // Fonts val FONT_ARIAL_PLAIN_14 = Font("Arial", Font.PLAIN, 14) - val FONT_ARIAL_PLAIN_12 = Font("Arial", Font.PLAIN, 12) + val FONT_ARIAL_PLAIN_12 = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) val FONT_ARIAL_BOLD_12 = Font("Arial", Font.BOLD, 12) + val SKILL_DISPLAY_ORDER = arrayOf(0,3,14,2,16,13,1,15,10,4,17,7,5,12,11,6,9,8,20,18,19,22,21,23) } var text: String = "" object HiscoresView { + + var hiScoreView: JPanel? = null class CustomSearchField(private val hiscoresPanel: JPanel) : Canvas() { private var cursorVisible: Boolean = true @@ -69,6 +80,7 @@ object HiscoresView { size = preferredSize minimumSize = preferredSize maximumSize = preferredSize + fillColor = COLOR_BACKGROUND_DARK } } @@ -125,7 +137,7 @@ object HiscoresView { } }) - Timer(500) { + Timer(1000) { cursorVisible = !cursorVisible if(plugin.StateManager.focusedView == "HISCORE_SEARCH_VIEW") repaint() @@ -140,7 +152,7 @@ object HiscoresView { val fm = g.fontMetrics val cursorX = fm.stringWidth(text) + 30 - imageCanvas?.let { canvas -> + imageCanvas.let { canvas -> val imgG = g.create(5, 5, canvas.width, canvas.height) canvas.paint(imgG) imgG.dispose() @@ -159,8 +171,10 @@ object HiscoresView { } fun searchPlayer(username: String) { - text = username - val apiUrl = "http://api.2009scape.org:3000/hiscores/playerSkills/1/${username.toLowerCase()}" + text = username.replace(" ", "_") + val apiUrl = "http://api.2009scape.org:3000/hiscores/playerSkills/1/${text.toLowerCase()}" + + updateHiscoresView(null, "Searching...") Thread { try { @@ -168,6 +182,10 @@ object HiscoresView { val connection = url.openConnection() as HttpURLConnection connection.requestMethod = "GET" + // If a request take longer than 5 seconds timeout. + connection.connectTimeout = 5000 + connection.readTimeout = 5000 + val responseCode = connection.responseCode if (responseCode == HttpURLConnection.HTTP_OK) { val reader = BufferedReader(InputStreamReader(connection.inputStream)) @@ -179,27 +197,45 @@ object HiscoresView { } } else { SwingUtilities.invokeLater { - showError("Player not found!") + showToast(hiscoresPanel, "Player not found!", JOptionPane.ERROR_MESSAGE) } } - } catch (e: Exception) { + } catch (e: SocketTimeoutException) { SwingUtilities.invokeLater { - showError("Error fetching data!") + showToast(hiscoresPanel, "Request timed out", JOptionPane.ERROR_MESSAGE) + } + } catch (e: Exception) { + // Handle other errors + SwingUtilities.invokeLater { + showToast(hiscoresPanel, "Error fetching data!", JOptionPane.ERROR_MESSAGE) } } }.start() } + private fun updatePlayerData(jsonResponse: String, username: String) { val hiscoresResponse = gson.fromJson(jsonResponse, HiscoresResponse::class.java) updateHiscoresView(hiscoresResponse, username) } - private fun updateHiscoresView(data: HiscoresResponse, username: String) { + private fun updateHiscoresView(data: HiscoresResponse?, username: String) { val playerNameLabel = findComponentByName(hiscoresPanel, "playerNameLabel") as? JPanel - val ironMode = data.info.iron_mode - playerNameLabel?.removeAll() // Clear previous components + var nameLabel = JLabel(formatHtmlLabelText(username, secondaryColor, "", primaryColor), JLabel.CENTER).apply { + font = Constants.FONT_ARIAL_BOLD_12 + foreground = Constants.COLOR_FOREGROUND_LIGHT + border = BorderFactory.createEmptyBorder(0, 6, 0, 0) // Top, Left, Bottom, Right padding + } + playerNameLabel?.add(nameLabel) + playerNameLabel?.revalidate() + playerNameLabel?.repaint() + + if(data == null) return; + + playerNameLabel?.removeAll() + + val ironMode = data.info.iron_mode if (ironMode != "0") { val ironmanBufferedImage = getBufferedImageFromSprite(Sprites.nameIcons[Constants.IRONMAN_SPRITE + ironMode.toInt() - 1]) @@ -213,11 +249,14 @@ object HiscoresView { playerNameLabel?.add(imageCanvas) } - val nameLabel = JLabel(username, JLabel.CENTER).apply { + val exp_multiplier = data.info.exp_multiplier + nameLabel = JLabel(formatHtmlLabelText(username, secondaryColor, " (${exp_multiplier}x)", primaryColor), JLabel.CENTER).apply { font = Constants.FONT_ARIAL_BOLD_12 foreground = Constants.COLOR_FOREGROUND_LIGHT + border = BorderFactory.createEmptyBorder(0, 6, 0, 0) // Top, Left, Bottom, Right padding } + playerNameLabel?.add(nameLabel) playerNameLabel?.revalidate() @@ -296,7 +335,7 @@ object HiscoresView { } } - fun createHiscoreSearchView(): JPanel { + fun createHiscoreSearchView() { val hiscorePanel = JPanel().apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) name = "HISCORE_SEARCH_VIEW" @@ -324,14 +363,13 @@ object HiscoresView { add(searchFieldWrapper) } - hiscorePanel.add(Helpers.Spacer(height = 10)) + hiscorePanel.add(Box.createVerticalStrut(10)) hiscorePanel.add(searchPanel) - hiscorePanel.add(Helpers.Spacer(height = 10)) + hiscorePanel.add(Box.createVerticalStrut(10)) - // Adding the player name panel in place of the filterPanel val playerNamePanel = JPanel().apply { - layout = FlowLayout(FlowLayout.CENTER) - background = VIEW_BACKGROUND_COLOR + layout = GridBagLayout() // This will center the JLabel both vertically and horizontally + background = WIDGET_COLOR preferredSize = Constants.FILTER_PANEL_DIMENSION maximumSize = preferredSize minimumSize = preferredSize @@ -339,7 +377,7 @@ object HiscoresView { } hiscorePanel.add(playerNamePanel) - hiscorePanel.add(Helpers.Spacer(height = 10)) + hiscorePanel.add(Box.createVerticalStrut(10)) val skillsPanel = JPanel(FlowLayout(FlowLayout.CENTER, 0, 0)).apply { background = Constants.COLOR_BACKGROUND_MEDIUM @@ -348,10 +386,10 @@ object HiscoresView { minimumSize = preferredSize } - for (i in 0 until 24) { + for (i in SKILL_DISPLAY_ORDER) { val skillPanel = JPanel().apply { layout = BorderLayout() - background = Constants.COLOR_SKILL_PANEL + background = COLOR_BACKGROUND_DARK preferredSize = Constants.SKILL_PANEL_DIMENSION maximumSize = preferredSize minimumSize = preferredSize @@ -362,8 +400,9 @@ object HiscoresView { val imageCanvas = bufferedImageSprite.let { ImageCanvas(it).apply { - preferredSize = Constants.IMAGE_CANVAS_DIMENSION - size = Constants.IMAGE_CANVAS_DIMENSION + preferredSize = SKILL_SPRITE_DIMENSION + size = SKILL_SPRITE_DIMENSION + fillColor = COLOR_BACKGROUND_DARK } } @@ -376,7 +415,7 @@ object HiscoresView { } val imageContainer = JPanel(FlowLayout(FlowLayout.CENTER, 5, 0)).apply { - background = Constants.COLOR_BACKGROUND_DARK + background = COLOR_BACKGROUND_DARK add(imageCanvas) add(numberLabel) } @@ -431,7 +470,7 @@ object HiscoresView { } val combatLevelPanel = JPanel(FlowLayout(FlowLayout.LEFT)).apply { - background = Constants.COLOR_BACKGROUND_DARK + background = COLOR_BACKGROUND_DARK add(combatLevelIcon) add(combatLevelLabel) } @@ -439,8 +478,9 @@ object HiscoresView { totalCombatPanel.add(totalLevelPanel) totalCombatPanel.add(combatLevelPanel) hiscorePanel.add(totalCombatPanel) + hiscorePanel.add(Box.createVerticalStrut(10)) - return hiscorePanel + hiScoreView = hiscorePanel; } data class HiscoresResponse( diff --git a/plugin-playground/src/main/kotlin/KondoKit/ImageCanvas.kt b/plugin-playground/src/main/kotlin/KondoKit/ImageCanvas.kt index 8923f08..3a9a9f3 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ImageCanvas.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ImageCanvas.kt @@ -1,5 +1,6 @@ package KondoKit +import KondoKit.plugin.Companion.WIDGET_COLOR import java.awt.Canvas import java.awt.Color import java.awt.Dimension @@ -8,31 +9,25 @@ import java.awt.image.BufferedImage class ImageCanvas(private val image: BufferedImage) : Canvas() { + var fillColor: Color = WIDGET_COLOR + init { - // Manually set the alpha value to 255 (fully opaque) only for pixels that are not fully transparent val width = image.width val height = image.height for (y in 0 until height) { for (x in 0 until width) { - // Retrieve the current pixel color val color = image.getRGB(x, y) - - // Check if the pixel is not fully transparent (i.e., color is not 0) if (color != 0) { - // Ensure the alpha is set to 255 (fully opaque) val newColor = (color and 0x00FFFFFF) or (0xFF shl 24) - - // Set the pixel with the updated color image.setRGB(x, y, newColor) } } } } - override fun paint(g: Graphics) { super.paint(g) - g.color = Color(27, 27, 27) + g.color = fillColor g.fillRect(0, 0, width, height) g.drawImage(image, 0, 0, width, height, this) } diff --git a/plugin-playground/src/main/kotlin/KondoKit/KondoKitUtils.kt b/plugin-playground/src/main/kotlin/KondoKit/KondoKitUtils.kt deleted file mode 100644 index 3ef3c39..0000000 --- a/plugin-playground/src/main/kotlin/KondoKit/KondoKitUtils.kt +++ /dev/null @@ -1,100 +0,0 @@ -package KondoKit - -import java.awt.Color -import java.lang.reflect.Field -import java.lang.reflect.ParameterizedType -import java.lang.reflect.Type - - -/* - This is used for the runtime editing of plugin variables. - To expose fields name them starting with `kondoExposed_` - When they are applied this will trigger an invoke of OnKondoValueUpdated() - if it is implemented. Check GroundItems plugin for an example. - */ - -object KondoKitUtils { - const val KONDO_PREFIX = "kondoExposed_" - - fun isKondoExposed(field: Field): Boolean { - return field.name.startsWith(KONDO_PREFIX) - } - - fun getKondoExposedFields(instance: Any): List { - val exposedFields: MutableList = ArrayList() - for (field in instance.javaClass.declaredFields) { - if (isKondoExposed(field)) { - exposedFields.add(field) - } - } - return exposedFields - } - - fun convertValue(type: Class<*>, genericType: Type?, value: String): Any { - return when { - type == Int::class.java -> value.toInt() - type == Double::class.java -> value.toDouble() - type == Boolean::class.java -> value.toBoolean() - type == Color::class.java -> convertToColor(value) - type == List::class.java && genericType is ParameterizedType -> { - val actualTypeArgument = genericType.actualTypeArguments.firstOrNull() - when { - value.isBlank() -> emptyList() // Handle empty string by returning an empty list - actualTypeArgument == Int::class.javaObjectType -> value.trim('[', ']').split(",").filter { it.isNotBlank() }.map { it.trim().toInt() } - actualTypeArgument == String::class.java -> value.trim('[', ']').split(",").filter { it.isNotBlank() }.map { it.trim() } - else -> throw IllegalArgumentException("Unsupported List type: $actualTypeArgument") - } - } - else -> value // Default to String - } - } - - - - fun convertToColor(value: String): Color { - val color = Color.decode(value) // Assumes value is in format "#RRGGBB" or "0xRRGGBB" - return color - } - - fun colorToHex(color: Color): String { - return "#%02x%02x%02x".format(color.red, color.green, color.blue) - } - - fun colorToIntArray(color: Color): IntArray { - return intArrayOf(color.red, color.green, color.blue) - } - - interface FieldObserver { - fun onFieldChange(field: Field, newValue: Any?) - } - - class FieldNotifier(private val plugin: Any) { - private val observers = mutableListOf() - - fun addObserver(observer: FieldObserver) { - observers.add(observer) - } - - fun notifyFieldChange(field: Field, newValue: Any?) { - for (observer in observers) { - observer.onFieldChange(field, newValue) - } - } - - fun setFieldValue(field: Field, value: Any?) { - field.isAccessible = true - field.set(plugin, value) - notifyFieldChange(field, value) - - try { - val onUpdateMethod = plugin::class.java.getMethod("OnKondoValueUpdated") - onUpdateMethod.invoke(plugin) - } catch (e: Exception) { - e.printStackTrace() - } - } - - - } - -} diff --git a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt index 9da6c6b..459b84f 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt @@ -1,5 +1,6 @@ package KondoKit +import KondoKit.Helpers.addMouseListenerToAll import KondoKit.Helpers.formatHtmlLabelText import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.XPTrackerView.wrappedWidget @@ -9,11 +10,11 @@ import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor import plugin.api.API -import rt4.NpcTypeList -import rt4.ObjStackNode -import rt4.Player -import rt4.SceneGraph +import rt4.* import java.awt.* +import java.awt.Font +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent import java.awt.image.BufferedImage import java.io.BufferedReader import java.io.InputStreamReader @@ -22,6 +23,7 @@ import java.net.URL import java.nio.charset.StandardCharsets import java.text.DecimalFormat import javax.swing.* +import kotlin.math.ceil object LootTrackerView { private const val SNAPSHOT_LIFESPAN = 10 @@ -31,10 +33,12 @@ object LootTrackerView { private val lootItemPanels = mutableMapOf>() private val npcKillCounts = mutableMapOf() private var totalTrackerWidget: XPWidget? = null - var lastConfirmedKillNpcId = -1; + var lastConfirmedKillNpcId = -1 + var customToolTipWindow: JWindow? = null + var lootTrackerView: JPanel? = null fun loadGEPrices(): Map { - return if (plugin.kondoExposed_useLiveGEPrices) { + return if (plugin.useLiveGEPrices) { try { println("LootTracker: Loading Remote GE Prices") val url = URL("https://cdn.2009scape.org/gedata/latest.json") @@ -69,7 +73,7 @@ object LootTrackerView { } else { try { println("LootTracker: Loading Local GE Prices") - BufferedReader(InputStreamReader(plugin::class.java.getResourceAsStream("item_configs.json"), StandardCharsets.UTF_8)) + BufferedReader(InputStreamReader(plugin::class.java.getResourceAsStream("res/item_configs.json"), StandardCharsets.UTF_8)) .useLines { lines -> val json = lines.joinToString("\n") val items = json.trim().removeSurrounding("[", "]").split("},").map { it.trim() + "}" } @@ -94,17 +98,34 @@ object LootTrackerView { - fun createLootTrackerView(): JPanel { - return JPanel().apply { - layout = FlowLayout(FlowLayout.CENTER, 0, 5) + fun createLootTrackerView() { + lootTrackerView = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) // Use BoxLayout on Y axis to stack widgets vertically background = VIEW_BACKGROUND_COLOR - preferredSize = Dimension(270, 700) - maximumSize = Dimension(270, 700) - minimumSize = Dimension(270, 700) add(Box.createVerticalStrut(5)) totalTrackerWidget = createTotalLootWidget() - add(wrappedWidget(totalTrackerWidget!!.panel)) - add(Helpers.Spacer(height = 15)) + + val wrapped = wrappedWidget(totalTrackerWidget!!.container) + val popupMenu = resetLootTrackerMenu() + + // Create a custom MouseListener + val rightClickListener = object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + if (e.isPopupTrigger) { + popupMenu.show(e.component, e.x, e.y) + } + } + + override fun mouseReleased(e: MouseEvent) { + if (e.isPopupTrigger) { + popupMenu.show(e.component, e.x, e.y) + } + } + } + addMouseListenerToAll(wrapped,rightClickListener) + wrapped.addMouseListener(rightClickListener) + add(wrapped) + add(Box.createVerticalStrut(10)) revalidate() repaint() } @@ -122,7 +143,7 @@ object LootTrackerView { totalTrackerWidget?.let { it.previousXp += newVal it.xpPerHourLabel.text = formatHtmlLabelText("Total Value: ", primaryColor, formatValue(it.previousXp) + " gp", secondaryColor) - it.panel.repaint() + it.container.repaint() } } @@ -132,7 +153,7 @@ object LootTrackerView { val l2 = createLabel(formatHtmlLabelText("Total Count: ", primaryColor, "0", secondaryColor)) return XPWidget( skillId = -1, - panel = createWidgetPanel(bufferedImageSprite,l2,l1), + container = createWidgetPanel(bufferedImageSprite,l2,l1), xpGainedLabel = l2, xpLeftLabel = JLabel(), actionsRemainingLabel = JLabel(), @@ -173,7 +194,7 @@ object LootTrackerView { private fun createLabel(text: String): JLabel { return JLabel(text).apply { - font = Font("Arial", Font.PLAIN, 11) + font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) horizontalAlignment = JLabel.LEFT } } @@ -189,9 +210,15 @@ object LootTrackerView { // Recalculate lootPanel size based on the number of unique items. val totalItems = lootItemPanels[npcName]?.size ?: 0 - val rowsNeeded = Math.ceil(totalItems / 6.0).toInt() - val lootPanelHeight = rowsNeeded * 36 + (rowsNeeded - 1) - lootPanel.preferredSize = Dimension(270, lootPanelHeight+10) + val rowsNeeded = ceil(totalItems / 6.0).toInt() + val lootPanelHeight = rowsNeeded * (40) + + val size = Dimension(lootPanel.width,lootPanelHeight+32) + lootPanel.parent.preferredSize = size + lootPanel.parent.minimumSize = size + lootPanel.parent.maximumSize = size + lootPanel.parent.revalidate() + lootPanel.parent.repaint() lootPanel.revalidate() lootPanel.repaint() @@ -205,21 +232,86 @@ object LootTrackerView { private fun createItemPanel(itemId: Int, quantity: Int): JPanel { val bufferedImageSprite = getBufferedImageFromSprite(API.GetObjSprite(itemId, quantity, true, 0, 0)) - return FixedSizePanel(Dimension(36, 32)).apply { + + // Create the panel for the item + val itemPanel = FixedSizePanel(Dimension(36, 32)).apply { preferredSize = Dimension(36, 32) background = WIDGET_COLOR minimumSize = preferredSize maximumSize = preferredSize - add(ImageCanvas(bufferedImageSprite).apply { + + val imageCanvas = ImageCanvas(bufferedImageSprite).apply { preferredSize = Dimension(36, 32) background = WIDGET_COLOR minimumSize = preferredSize maximumSize = preferredSize - }, BorderLayout.CENTER) + } + + // Add the imageCanvas to the panel + add(imageCanvas, BorderLayout.CENTER) + + // Put the itemId as a property for reference putClientProperty("itemId", itemId) + + // Add mouse listener for custom hover text + imageCanvas.addMouseListener(object : MouseAdapter() { + override fun mouseEntered(e: MouseEvent) { + // Show custom tooltip when the mouse enters the component + showCustomToolTip(e.point, itemId,quantity,imageCanvas) + } + + override fun mouseExited(e: MouseEvent) { + // Hide tooltip when mouse exits + hideCustomToolTip() + } + }) } + + return itemPanel } + // Function to show the custom tooltip + fun showCustomToolTip(location: Point, itemId: Int, quantity: Int, parentComponent: ImageCanvas) { + var itemDef = ObjTypeList.get(itemId) + val gePricePerItem = gePriceMap[itemDef.id.toString()]?.toInt() ?: 0 + val totalGePrice = gePricePerItem * quantity + val totalHaPrice = itemDef.cost * quantity + val geText = if (quantity > 1) " (${gePricePerItem} ea)" else "" + val haText = if (quantity > 1) " (${itemDef.cost} ea)" else "" + + val text = "
" + + "${itemDef.name} x $quantity
" + + "GE: $totalGePrice ${geText}
" + + "HA: $totalHaPrice ${haText}
" + + val _font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) + val c = Color(50,50,50) + if (customToolTipWindow == null) { + customToolTipWindow = JWindow().apply { + contentPane = JLabel(text).apply { + border = BorderFactory.createLineBorder(Color.BLACK) + isOpaque = true + background = c + foreground = Color.WHITE + font = _font + } + pack() + } + } + + // Calculate the tooltip location relative to the parent component + val screenLocation = parentComponent.locationOnScreen + customToolTipWindow!!.setLocation(screenLocation.x + location.x, screenLocation.y + location.y + 20) + customToolTipWindow!!.isVisible = true + } + + // Function to hide the custom tooltip + fun hideCustomToolTip() { + customToolTipWindow?.isVisible = false + customToolTipWindow = null // Nullify the global instance + } + + private fun updateItemPanelIcon(panel: JPanel, itemId: Int, quantity: Int) { panel.removeAll() panel.add(createItemPanel(itemId, quantity).components[0], BorderLayout.CENTER) @@ -308,9 +400,8 @@ object LootTrackerView { private fun handleNewDrops(npcName: String, newDrops: Set, lootTrackerView: JPanel) { findLootItemsPanel(lootTrackerView, npcName)?.let { } ?: run { - // Panel doesn't exist, so create and add it lootTrackerView.add(createLootFrame(npcName)) - lootTrackerView.add(Helpers.Spacer(height = 15)) + lootTrackerView.add(Box.createVerticalStrut(10)) lootTrackerView.revalidate() lootTrackerView.repaint() } @@ -330,14 +421,15 @@ object LootTrackerView { val childFramePanel = JPanel().apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) background = WIDGET_COLOR - minimumSize = Dimension(270, 0) - maximumSize = Dimension(270, 700) + minimumSize = Dimension(230, 0) + maximumSize = Dimension(230, 700) + name = "HELLO_WORLD" } val labelPanel = JPanel(BorderLayout()).apply { background = Color(21, 21, 21) border = BorderFactory.createEmptyBorder(5, 5, 5, 5) - maximumSize = Dimension(270, 24) + maximumSize = Dimension(230, 24) minimumSize = maximumSize preferredSize = maximumSize } @@ -345,14 +437,14 @@ object LootTrackerView { val killCount = npcKillCounts.getOrPut(npcName) { 0 } val countLabel = JLabel(formatHtmlLabelText(npcName, secondaryColor, " x $killCount", primaryColor)).apply { foreground = Color(200, 200, 200) - font = Font("Arial", Font.PLAIN, 12) + font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) horizontalAlignment = JLabel.LEFT name = "killCountLabel_$npcName" } val valueLabel = JLabel("0 gp").apply { foreground = Color(200, 200, 200) - font = Font("Arial", Font.PLAIN, 12) + font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) horizontalAlignment = JLabel.RIGHT name = "valueLabel_$npcName" } @@ -370,19 +462,115 @@ object LootTrackerView { lootItemPanels[npcName] = mutableMapOf() - // Determine number of items and adjust size of lootPanel - val totalItems = lootItemPanels[npcName]?.size ?: 0 - val rowsNeeded = Math.ceil(totalItems / 6.0).toInt() - val lootPanelHeight = rowsNeeded * 36 + (rowsNeeded - 1) // Height per row = 36 + spacing - lootPanel.preferredSize = Dimension(270, lootPanelHeight+10) - childFramePanel.add(labelPanel) childFramePanel.add(lootPanel) - childFramePanel.add(lootPanel) + val popupMenu = removeLootFrameMenu(childFramePanel, npcName) + + // Create a custom MouseListener + val rightClickListener = object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + if (e.isPopupTrigger) { + popupMenu.show(e.component, e.x, e.y) + } + } + + override fun mouseReleased(e: MouseEvent) { + if (e.isPopupTrigger) { + popupMenu.show(e.component, e.x, e.y) + } + } + } + + labelPanel.addMouseListener(rightClickListener) return childFramePanel } + fun removeLootFrameMenu(toRemove: JPanel, npcName: String): JPopupMenu { + // Create a popup menu + val popupMenu = JPopupMenu() + val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) + + popupMenu.background = Color(45, 45, 45) + + // Create menu items with custom font and colors + val menuItem1 = JMenuItem("Remove").apply { + font = rFont // Set custom font + background = Color(45, 45, 45) // Dark background for item + foreground = Color(220, 220, 220) // Light text color for item + } + popupMenu.add(menuItem1) + menuItem1.addActionListener { + lootItemPanels[npcName]?.clear() + npcKillCounts[npcName] = 0 + lootTrackerView?.let { parent -> + val components = parent.components + val toRemoveIndex = components.indexOf(toRemove) + if (toRemoveIndex >= 0 && toRemoveIndex < components.size - 1) { + val nextComponent = components[toRemoveIndex + 1] + if (nextComponent is Box.Filler) { + // Nasty way to remove the Box.createVerticalStrut(10) after + // the lootpanel. + parent.remove(nextComponent) + } + } + parent.remove(toRemove) + parent.revalidate() + parent.repaint() + } + } + return popupMenu + } + + + fun resetLootTrackerMenu(): JPopupMenu { + // Create a popup menu + val popupMenu = JPopupMenu() + val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) + + popupMenu.background = Color(45, 45, 45) + + // Create menu items with custom font and colors + val menuItem1 = JMenuItem("Reset Loot Tracker").apply { + font = rFont // Set custom font + background = Color(45, 45, 45) // Dark background for item + foreground = Color(220, 220, 220) // Light text color for item + } + popupMenu.add(menuItem1) + menuItem1.addActionListener { + lootTrackerView?.removeAll() + npcKillCounts.clear() + lootItemPanels.clear() + totalTrackerWidget = createTotalLootWidget() + + val wrapped = wrappedWidget(totalTrackerWidget!!.container) + val _popupMenu = resetLootTrackerMenu() + + // Create a custom MouseListener + val rightClickListener = object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + if (e.isPopupTrigger) { + _popupMenu.show(e.component, e.x, e.y) + } + } + + override fun mouseReleased(e: MouseEvent) { + if (e.isPopupTrigger) { + _popupMenu.show(e.component, e.x, e.y) + } + } + } + addMouseListenerToAll(wrapped,rightClickListener) + wrapped.addMouseListener(rightClickListener) + lootTrackerView?.add(Box.createVerticalStrut(5)) + lootTrackerView?.add(wrapped) + lootTrackerView?.add(Box.createVerticalStrut(10)) + lootTrackerView?.revalidate() + lootTrackerView?.repaint() + } + return popupMenu + } + class FixedSizePanel(private val fixedSize: Dimension) : JPanel() { override fun getPreferredSize(): Dimension { diff --git a/plugin-playground/src/main/kotlin/KondoKit/ProgressBar.kt b/plugin-playground/src/main/kotlin/KondoKit/ProgressBar.kt index 0554641..f5df980 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ProgressBar.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ProgressBar.kt @@ -2,18 +2,19 @@ package KondoKit import java.awt.Canvas import java.awt.Color +import java.awt.Dimension import java.awt.Font import java.awt.Graphics class ProgressBar( - private var progress: Double, - private val barColor: Color, - private var currentLevel: Int = 0, - private var nextLevel: Int = 1 + private var progress: Double, + private val barColor: Color, + private var currentLevel: Int = 0, + private var nextLevel: Int = 1 ) : Canvas() { init { - font = Font("Arial", Font.PLAIN, 12) + font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) } override fun paint(g: Graphics) { @@ -25,22 +26,32 @@ class ProgressBar( g.fillRect(0, 0, width, this.height) // Draw the unfilled part of the progress bar - g.color = Color(100, 100, 100) + g.color = Color(61, 56, 49) // from Runelite g.fillRect(width, 0, this.width - width, this.height) + // Variables for text position + val textY = this.height / 2 + 6 + // Draw the current level on the far left - g.color = Color(255, 255, 255) - g.drawString("Lvl. $currentLevel", 5, this.height / 2 + 4) + drawTextWithShadow(g, "Lvl. $currentLevel", 5, textY, Color(255, 255, 255)) // Draw the percentage in the middle val percentageText = String.format("%.2f%%", progress) val percentageWidth = g.fontMetrics.stringWidth(percentageText) - g.drawString(percentageText, (this.width - percentageWidth) / 2, this.height / 2 + 4) + drawTextWithShadow(g, percentageText, (this.width - percentageWidth) / 2, textY, Color(255, 255, 255)) // Draw the next level on the far right val nextLevelText = "Lvl. $nextLevel" val nextLevelWidth = g.fontMetrics.stringWidth(nextLevelText) - g.drawString(nextLevelText, this.width - nextLevelWidth - 5, this.height / 2 + 4) + drawTextWithShadow(g, nextLevelText, this.width - nextLevelWidth - 5, textY, Color(255, 255, 255)) + } + + override fun getPreferredSize(): Dimension { + return Dimension(220, 16) // Force the height to 16px, width can be anything appropriate + } + + override fun getMinimumSize(): Dimension { + return Dimension(220, 16) // Force the minimum height to 16px, width can be smaller } fun updateProgress(newProgress: Double, currentLevel: Int, nextLevel: Int, isVisible : Boolean) { @@ -50,4 +61,15 @@ class ProgressBar( if(isVisible) repaint() } + + // Helper function to draw text with a shadow effect + private fun drawTextWithShadow(g: Graphics, text: String, x: Int, y: Int, textColor: Color) { + // Draw shadow (black text with -1 x and -1 y offset) + g.color = Color(0, 0, 0) + g.drawString(text, x + 1, y + 1) + + // Draw actual text on top + g.color = textColor + g.drawString(text, x, y) + } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt index a9227c9..40bad3d 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt @@ -1,35 +1,50 @@ package KondoKit -import KondoKit.KondoKitUtils.convertValue +import KondoKit.Helpers.convertValue +import KondoKit.Helpers.showToast import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor import plugin.Plugin +import plugin.PluginInfo import plugin.PluginRepository import java.awt.* -import java.lang.reflect.Field +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent import java.util.* import java.util.Timer import javax.swing.* +import kotlin.math.ceil + +/* + This is used for the runtime editing of plugin variables. + To expose fields add the @Exposed annotation. + When they are applied this will trigger an invoke of OnKondoValueUpdated() + if it is implemented. Check GroundItems plugin for an example. + */ + object ReflectiveEditorView { - fun createReflectiveEditorView(): JPanel { + var reflectiveEditorView: JPanel? = null + fun createReflectiveEditorView() { val reflectiveEditorPanel = JPanel(BorderLayout()) reflectiveEditorPanel.background = VIEW_BACKGROUND_COLOR reflectiveEditorPanel.add(Box.createVerticalStrut(5)) reflectiveEditorPanel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10) - return reflectiveEditorPanel + reflectiveEditorView = reflectiveEditorPanel + addPlugins(reflectiveEditorView!!) } fun addPlugins(reflectiveEditorView: JPanel) { + reflectiveEditorView.removeAll() // clear previous try { val loadedPluginsField = PluginRepository::class.java.getDeclaredField("loadedPlugins") loadedPluginsField.isAccessible = true val loadedPlugins = loadedPluginsField.get(null) as HashMap<*, *> - for ((_, plugin) in loadedPlugins) { - addPluginToEditor(reflectiveEditorView, plugin as Plugin) + for ((pluginInfo, plugin) in loadedPlugins) { + addPluginToEditor(reflectiveEditorView, pluginInfo as PluginInfo, plugin as Plugin) } } catch (e: Exception) { e.printStackTrace() @@ -38,112 +53,214 @@ object ReflectiveEditorView { reflectiveEditorView.repaint() } - private fun addPluginToEditor(reflectiveEditorView: JPanel, plugin: Any) { + private fun addPluginToEditor(reflectiveEditorView: JPanel, pluginInfo : PluginInfo, plugin: Plugin) { reflectiveEditorView.layout = BoxLayout(reflectiveEditorView, BoxLayout.Y_AXIS) - val fieldNotifier = KondoKitUtils.FieldNotifier(plugin) - val exposedFields = KondoKitUtils.getKondoExposedFields(plugin) - - if (exposedFields.isNotEmpty()) { - val packageName = plugin.javaClass.`package`.name - val labelPanel = JPanel(BorderLayout()) - labelPanel.maximumSize = Dimension(Int.MAX_VALUE, 30) // Adjust height to be minimal - labelPanel.background = VIEW_BACKGROUND_COLOR // Ensure it matches the overall background - labelPanel.border = BorderFactory.createEmptyBorder(5, 0, 5, 0) - - val label = JLabel("$packageName", SwingConstants.CENTER) - label.foreground = primaryColor - label.font = Font("Arial", Font.BOLD, 14) - labelPanel.add(label, BorderLayout.CENTER) - reflectiveEditorView.add(labelPanel) + val fieldNotifier = Helpers.FieldNotifier(plugin) + val exposedFields = plugin.javaClass.declaredFields.filter { field -> + field.annotations.any { annotation -> + annotation.annotationClass.simpleName == "Exposed" + } } - for (field in exposedFields) { - field.isAccessible = true + if (exposedFields.isNotEmpty()) { - val fieldPanel = JPanel() - fieldPanel.layout = GridBagLayout() - fieldPanel.background = WIDGET_COLOR // Match the background for minimal borders - fieldPanel.foreground = secondaryColor - fieldPanel.border = BorderFactory.createEmptyBorder(5, 0, 5, 0) // No visible border, just spacing - fieldPanel.maximumSize = Dimension(Int.MAX_VALUE, 40) + val packageName = plugin.javaClass.`package`.name + val version = pluginInfo.version + val labelPanel = JPanel(BorderLayout()) + labelPanel.maximumSize = Dimension(Int.MAX_VALUE, 30) + labelPanel.background = VIEW_BACKGROUND_COLOR + labelPanel.border = BorderFactory.createEmptyBorder(5, 0, 0, 0) - val gbc = GridBagConstraints() - gbc.insets = Insets(0, 5, 0, 5) // Less padding, more minimal spacing + val label = JLabel("$packageName v$version", SwingConstants.CENTER) + label.foreground = primaryColor + label.font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) + labelPanel.add(label, BorderLayout.CENTER) + label.isOpaque = true + label.background = Color(21, 21, 21) + reflectiveEditorView.add(labelPanel) - val label = JLabel(field.name.removePrefix(KondoKitUtils.KONDO_PREFIX).capitalize()) - label.foreground = secondaryColor - gbc.gridx = 0 - gbc.gridy = 0 - gbc.weightx = 0.0 - gbc.anchor = GridBagConstraints.WEST - fieldPanel.add(label, gbc) + for (field in exposedFields) { + field.isAccessible = true - val textField = JTextField(field.get(plugin)?.toString() ?: "") - textField.background = VIEW_BACKGROUND_COLOR - textField.foreground = secondaryColor - textField.border = BorderFactory.createLineBorder(WIDGET_COLOR, 1) // Subtle border - gbc.gridx = 1 - gbc.gridy = 0 - gbc.weightx = 1.0 - gbc.fill = GridBagConstraints.HORIZONTAL - fieldPanel.add(textField, gbc) - - val applyButton = JButton("Apply") - applyButton.background = primaryColor - applyButton.foreground = VIEW_BACKGROUND_COLOR - applyButton.border = BorderFactory.createLineBorder(primaryColor, 1) - gbc.gridx = 2 - gbc.gridy = 0 - gbc.weightx = 0.0 - gbc.fill = GridBagConstraints.NONE - applyButton.addActionListener { - try { - val newValue = convertValue(field.type, field.genericType, textField.text) - fieldNotifier.setFieldValue(field, newValue) - JOptionPane.showMessageDialog( - null, - "${field.name.removePrefix(KondoKitUtils.KONDO_PREFIX)} updated successfully!" - ) - } catch (e: Exception) { - JOptionPane.showMessageDialog( - null, - "Failed to update ${field.name.removePrefix(KondoKitUtils.KONDO_PREFIX)}: ${e.message}", - "Error", - JOptionPane.ERROR_MESSAGE - ) + // Get the "Exposed" annotation specifically and retrieve its description, if available + val exposedAnnotation = field.annotations.firstOrNull { annotation -> + annotation.annotationClass.simpleName == "Exposed" } - } - fieldPanel.add(applyButton, gbc) - reflectiveEditorView.add(fieldPanel) + val description = exposedAnnotation?.let { annotation -> + try { + val descriptionField = annotation.annotationClass.java.getMethod("description") + descriptionField.invoke(annotation) as String + } catch (e: NoSuchMethodException) { + "" // No description method, return empty string + } + } ?: "" - var previousValue = field.get(plugin)?.toString() - val timer = Timer() - timer.schedule(object : TimerTask() { - override fun run() { - val currentValue = field.get(plugin)?.toString() - if (currentValue != previousValue) { - previousValue = currentValue - SwingUtilities.invokeLater { - fieldNotifier.notifyFieldChange(field, currentValue) + val fieldPanel = JPanel() + fieldPanel.layout = GridBagLayout() + fieldPanel.background = WIDGET_COLOR + fieldPanel.foreground = secondaryColor + fieldPanel.border = BorderFactory.createEmptyBorder(5, 0, 5, 0) + fieldPanel.maximumSize = Dimension(Int.MAX_VALUE, 40) + + val gbc = GridBagConstraints() + gbc.insets = Insets(0, 5, 0, 5) + + val label = JLabel(field.name.capitalize()) + label.foreground = secondaryColor + gbc.gridx = 0 + gbc.gridy = 0 + gbc.weightx = 0.0 + label.font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) + gbc.anchor = GridBagConstraints.WEST + fieldPanel.add(label, gbc) + + // Create appropriate input component based on field type + val inputComponent: JComponent = when { + field.type == Boolean::class.javaPrimitiveType || field.type == java.lang.Boolean::class.java -> JCheckBox().apply { + isSelected = field.get(plugin) as Boolean + } + + field.type.isEnum -> JComboBox((field.type.enumConstants as Array>)).apply { + selectedItem = field.get(plugin) + } + + field.type == Int::class.javaPrimitiveType || field.type == Integer::class.java -> JSpinner(SpinnerNumberModel(field.get(plugin) as Int, Int.MIN_VALUE, Int.MAX_VALUE, 1)) + field.type == Float::class.javaPrimitiveType || field.type == Double::class.javaPrimitiveType || field.type == java.lang.Float::class.java || field.type == java.lang.Double::class.java -> JSpinner(SpinnerNumberModel((field.get(plugin) as Number).toDouble(), -Double.MAX_VALUE, Double.MAX_VALUE, 0.1)) + else -> JTextField(field.get(plugin)?.toString() ?: "") + } + + // Add mouse listener to the label only if a description is available + if (description.isNotBlank()) { + label.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) + label.addMouseListener(object : MouseAdapter() { + override fun mouseEntered(e: MouseEvent) { + showCustomToolTip(description, label) + } + + override fun mouseExited(e: MouseEvent) { + customToolTipWindow?.isVisible = false + } + }) + } + + gbc.gridx = 1 + gbc.gridy = 0 + gbc.weightx = 1.0 + gbc.fill = GridBagConstraints.HORIZONTAL + fieldPanel.add(inputComponent, gbc) + + val applyButton = JButton("\u2714").apply { + maximumSize = Dimension(Int.MAX_VALUE, 10) + } + gbc.gridx = 2 + gbc.gridy = 0 + gbc.weightx = 0.0 + gbc.fill = GridBagConstraints.NONE + applyButton.addActionListener { + try { + val newValue = when (inputComponent) { + is JCheckBox -> inputComponent.isSelected + is JComboBox<*> -> inputComponent.selectedItem + is JSpinner -> inputComponent.value + is JTextField -> convertValue(field.type, field.genericType, inputComponent.text) + else -> throw IllegalArgumentException("Unsupported input component type") + } + fieldNotifier.setFieldValue(field, newValue) + showToast( + reflectiveEditorView, + "${field.name} updated successfully!" + ) + } catch (e: Exception) { + showToast( + reflectiveEditorView, + "Failed to update ${field.name}: ${e.message}", + JOptionPane.ERROR_MESSAGE + ) + } + } + + fieldPanel.add(applyButton, gbc) + reflectiveEditorView.add(fieldPanel) + + // Track field changes in real-time and update UI + var previousValue = field.get(plugin)?.toString() + val timer = Timer() + timer.schedule(object : TimerTask() { + override fun run() { + val currentValue = field.get(plugin)?.toString() + if (currentValue != previousValue) { + previousValue = currentValue + SwingUtilities.invokeLater { + // Update the inputComponent based on the new value + when (inputComponent) { + is JCheckBox -> inputComponent.isSelected = field.get(plugin) as Boolean + is JComboBox<*> -> inputComponent.selectedItem = field.get(plugin) + is JSpinner -> inputComponent.value = field.get(plugin) + is JTextField -> inputComponent.text = field.get(plugin)?.toString() ?: "" + } + } } } - } - }, 0, 1000) + }, 0, 1000) // Poll every 1000 milliseconds (1 second) + } - fieldNotifier.addObserver(object : KondoKitUtils.FieldObserver { - override fun onFieldChange(field: Field, newValue: Any?) { - if (field.name.removePrefix(KondoKitUtils.KONDO_PREFIX).equals(label.text, ignoreCase = true)) { - textField.text = newValue?.toString() ?: "" - textField.revalidate() - textField.repaint() - } - } - }) - } - if (exposedFields.isNotEmpty()) { - reflectiveEditorView.add(Box.createVerticalStrut(10)) + if (exposedFields.isNotEmpty()) { + reflectiveEditorView.add(Box.createVerticalStrut(5)) + } } + reflectiveEditorView.revalidate() + if(KondoKit.plugin.StateManager.focusedView == "REFLECTIVE_EDITOR_VIEW") + reflectiveEditorView.repaint() } -} + + var customToolTipWindow: JWindow? = null + + fun showCustomToolTip(text: String, component: JComponent) { + val _font = Font("RuneScape Small", Font.PLAIN, 16) + val backgroundColor = Color(50, 50, 50) + val maxWidth = 150 + val lineHeight = 16 + + // Create a dummy JLabel to get FontMetrics for the font used in the tooltip + val dummyLabel = JLabel() + dummyLabel.font = _font + val fontMetrics = dummyLabel.getFontMetrics(_font) + + // Calculate the approximate width of the text + val textWidth = fontMetrics.stringWidth(text) + + // Calculate the number of lines required based on the text width and max tooltip width + val numberOfLines = ceil(textWidth.toDouble() / maxWidth).toInt() + + // Calculate the required height of the tooltip + val requiredHeight = numberOfLines * lineHeight + 6 // Adding some padding + + if (customToolTipWindow == null) { + customToolTipWindow = JWindow().apply { + contentPane = JLabel("
$text
").apply { + border = BorderFactory.createLineBorder(Color.BLACK) + isOpaque = true + background = backgroundColor + foreground = Color.WHITE + font = _font + maximumSize = Dimension(maxWidth, Int.MAX_VALUE) + preferredSize = Dimension(maxWidth, requiredHeight) + } + pack() + } + } else { + // Update the tooltip text + val label = customToolTipWindow!!.contentPane as JLabel + label.text = "
$text
" + label.preferredSize = Dimension(maxWidth, requiredHeight) + customToolTipWindow!!.pack() + } + + // Position the tooltip near the component + val locationOnScreen = component.locationOnScreen + customToolTipWindow!!.setLocation(locationOnScreen.x, locationOnScreen.y + 15) + customToolTipWindow!!.isVisible = true + } +} \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt new file mode 100644 index 0000000..44467a7 --- /dev/null +++ b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt @@ -0,0 +1,154 @@ +package KondoKit + +import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR +import rt4.GameShell.frame +import java.awt.Color +import java.awt.Graphics +import java.awt.Graphics2D +import java.awt.Rectangle +import java.awt.event.* +import java.util.* +import javax.swing.JPanel + +class ScrollablePanel(private val content: JPanel) : JPanel() { + private var lastMouseY = 0 + private var currentOffsetY = 0 + private var scrollbarHeight = 0 + private var scrollbarY = 0 + private var showScrollbar = false + private var draggingScrollPill = false + + // Define a buffer for the view height (extra space for smoother scrolling) + private val viewBuffer = -30 + + init { + layout = null + background = VIEW_BACKGROUND_COLOR // Color.red color can be set to debug + + // Initial content bounds + content.bounds = Rectangle(0, 0, 242, content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer)) + add(content) + + // Add listeners for scrolling interactions + addMouseListener(object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + lastMouseY = e.y + if (showScrollbar && e.x in (242 - 10)..242 && e.y in scrollbarY..(scrollbarY + scrollbarHeight)) { + draggingScrollPill = true + } + } + + override fun mouseReleased(e: MouseEvent) { + draggingScrollPill = false + } + }) + + addMouseMotionListener(object : MouseMotionAdapter() { + override fun mouseDragged(e: MouseEvent) { + val deltaY = e.y - lastMouseY + if (draggingScrollPill && showScrollbar) { + val viewHeight = frame.height + val contentHeight = content.height + val scrollRatio = contentHeight.toDouble() / viewHeight + scrollContent((deltaY * scrollRatio).toInt()) + } else if (showScrollbar) { + scrollContent(deltaY) + } + lastMouseY = e.y + } + }) + + addMouseWheelListener { e -> + if (showScrollbar) { + scrollContent(-e.wheelRotation * 20) + } + } + + // Timer to periodically check and update scrollbar status + Timer().schedule(object : TimerTask() { + override fun run() { + updateScrollbar() + } + }, 0, 1000) + + // Component listener for resizing the frame + frame.addComponentListener(object : ComponentAdapter() { + override fun componentResized(e: ComponentEvent) { + handleResize() + } + }) + } + + private fun handleResize() { + // Ensure the ScrollablePanel resizes with the frame + bounds = Rectangle(0, 0, 242, frame.height) + + // Dynamically update content bounds and scrollbar on frame resize with buffer + content.bounds = Rectangle(0, 0, 242, content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer)) + showScrollbar = content.height > frame.height + + currentOffsetY = 0 + + content.setLocation(0, currentOffsetY) + updateScrollbar() + + revalidate() + repaint() + } + + private fun scrollContent(deltaY: Int) { + if (!showScrollbar) { + currentOffsetY = 0 + content.setLocation(0, currentOffsetY) + return + } + + currentOffsetY += deltaY + + // Apply buffer to maxOffset + val maxOffset = (frame.height - content.height + viewBuffer).coerceAtMost(0) + currentOffsetY = currentOffsetY.coerceAtMost(0).coerceAtLeast(maxOffset) + + content.setLocation(0, currentOffsetY) + + val contentHeight = content.height + val viewHeight = frame.height + viewBuffer + val scrollableRatio = viewHeight.toDouble() / contentHeight + scrollbarY = ((-currentOffsetY / contentHeight.toDouble()) * viewHeight).toInt() + scrollbarHeight = (viewHeight * scrollableRatio).toInt().coerceAtLeast(20) + + repaint() + } + + private fun updateScrollbar() { + showScrollbar = content.height > frame.height + + val contentHeight = content.height + val viewHeight = frame.height + viewBuffer + + if (showScrollbar) { + val scrollableRatio = viewHeight.toDouble() / contentHeight + scrollbarY = ((-currentOffsetY / contentHeight.toDouble()) * viewHeight).toInt() + scrollbarHeight = (viewHeight * scrollableRatio).toInt().coerceAtLeast(20) + } else { + scrollbarY = 0 + scrollbarHeight = 0 + } + + repaint() + } + + override fun paintComponent(g: Graphics) { + super.paintComponent(g) + } + + override fun paintChildren(g: Graphics) { + super.paintChildren(g) + if (showScrollbar) { + val g2 = g as Graphics2D + val scrollbarX = 238 + g2.color = Color(64, 64, 64) + g2.fillRect(scrollbarX, scrollbarY, 2, scrollbarHeight) + } + } +} diff --git a/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt index 0472ce9..ff41e11 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt @@ -4,32 +4,36 @@ import KondoKit.Helpers.formatHtmlLabelText import KondoKit.Helpers.formatNumber import KondoKit.Helpers.getProgressBarColor import KondoKit.Helpers.getSpriteId +import KondoKit.Helpers.addMouseListenerToAll import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.plugin.Companion.IMAGE_SIZE +import KondoKit.plugin.Companion.LVL_ICON import KondoKit.plugin.Companion.TOTAL_XP_WIDGET_SIZE import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_SIZE -import KondoKit.plugin.Companion.kondoExposed_playerXPMultiplier +import KondoKit.plugin.Companion.playerXPMultiplier import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor -import KondoKit.plugin.StateManager.totalXPWidget import plugin.api.API import java.awt.* +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent import java.io.BufferedReader import java.io.InputStreamReader import java.nio.charset.StandardCharsets -import javax.swing.Box -import javax.swing.BoxLayout -import javax.swing.JLabel -import javax.swing.JPanel +import javax.swing.* object XPTrackerView { - private val COMBAT_SKILLS = intArrayOf(0,1,2,3,4) + val xpWidgets: MutableMap = HashMap() + var totalXPWidget: XPWidget? = null + val initialXP: MutableMap = HashMap() + var xpTrackerView: JPanel? = null + val npcHitpointsMap: Map = try { - BufferedReader(InputStreamReader(plugin::class.java.getResourceAsStream("npc_hitpoints_map.json"), StandardCharsets.UTF_8)) + BufferedReader(InputStreamReader(plugin::class.java.getResourceAsStream("res/npc_hitpoints_map.json"), StandardCharsets.UTF_8)) .useLines { lines -> val json = lines.joinToString("\n") val pairs = json.trim().removeSurrounding("{", "}").split(",") @@ -74,8 +78,8 @@ object XPTrackerView { if(LootTrackerView.lastConfirmedKillNpcId != -1 && npcHitpointsMap.isNotEmpty()) { val npcHP = npcHitpointsMap[LootTrackerView.lastConfirmedKillNpcId] val xpPerKill = when (xpWidget.skillId) { - 3 -> kondoExposed_playerXPMultiplier * (npcHP ?: 1) // Hitpoints - else -> kondoExposed_playerXPMultiplier * (npcHP ?: 1) * 4 // Combat XP for other skills + 3 -> playerXPMultiplier * (npcHP ?: 1) // Hitpoints + else -> playerXPMultiplier * (npcHP ?: 1) * 4 // Combat XP for other skills } val remainingKills = xpLeft / xpPerKill xpWidget.actionsRemainingLabel.text = formatHtmlLabelText("Kills: ", primaryColor, remainingKills.toString(), secondaryColor) @@ -96,20 +100,57 @@ object XPTrackerView { xpWidget.previousXp = xp if (plugin.StateManager.focusedView == "XP_TRACKER_VIEW") - xpWidget.panel.repaint() + xpWidget.container.repaint() } private fun updateTotalXPWidget(xpGainedSinceLastUpdate: Int) { - val totalXPWidget = plugin.StateManager.totalXPWidget ?: return + val totalXPWidget = totalXPWidget ?: return totalXPWidget.totalXpGained += xpGainedSinceLastUpdate val formattedXp = formatNumber(totalXPWidget.totalXpGained) totalXPWidget.xpGainedLabel.text = formatHtmlLabelText("Gained: ", primaryColor, formattedXp, secondaryColor) if (plugin.StateManager.focusedView == "XP_TRACKER_VIEW") - totalXPWidget.panel.repaint() + totalXPWidget.container.repaint() } + fun resetXPTracker(xpTrackerView : JPanel){ + + // Redo logic here + xpTrackerView.removeAll() + val popupMenu = createResetMenu() + + // Create a custom MouseListener + val rightClickListener = object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + if (e.isPopupTrigger) { + popupMenu.show(e.component, e.x, e.y) + } + } + + override fun mouseReleased(e: MouseEvent) { + if (e.isPopupTrigger) { + popupMenu.show(e.component, e.x, e.y) + } + } + } + + // Create the XP widget + totalXPWidget = createTotalXPWidget() + val wrapped = wrappedWidget(totalXPWidget!!.container) + addMouseListenerToAll(wrapped,rightClickListener) + wrapped.addMouseListener(rightClickListener) + xpTrackerView.add(Box.createVerticalStrut(5)) + xpTrackerView.add(wrapped) + xpTrackerView.add(Box.createVerticalStrut(5)) + + initialXP.clear() + xpWidgets.clear() + + xpTrackerView.revalidate() + if (plugin.StateManager.focusedView == "XP_TRACKER_VIEW") + xpTrackerView.repaint() + } fun createTotalXPWidget(): XPWidget { val widgetPanel = Panel().apply { @@ -120,11 +161,9 @@ object XPTrackerView { minimumSize = TOTAL_XP_WIDGET_SIZE } - val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(898)) - + val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(LVL_ICON)) val imageContainer = Panel(FlowLayout()).apply { - background = WIDGET_COLOR preferredSize = IMAGE_SIZE maximumSize = IMAGE_SIZE minimumSize = IMAGE_SIZE @@ -133,15 +172,14 @@ object XPTrackerView { bufferedImageSprite.let { image -> val imageCanvas = ImageCanvas(image).apply { - background = WIDGET_COLOR - preferredSize = Dimension(image.width, image.height) - maximumSize = Dimension(image.width, image.height) - minimumSize = Dimension(image.width, image.height) - size = Dimension(image.width, image.height) + preferredSize = Dimension(bufferedImageSprite.width, bufferedImageSprite.height) + maximumSize = preferredSize + minimumSize = preferredSize + size = preferredSize } imageContainer.add(imageCanvas) - imageContainer.size = Dimension(image.width, image.height) + imageContainer.size = Dimension(bufferedImageSprite.width, bufferedImageSprite.height) imageContainer.revalidate() if(plugin.StateManager.focusedView == "XP_TRACKER_VIEW") @@ -149,14 +187,13 @@ object XPTrackerView { } val textPanel = Panel().apply { - layout = GridLayout(2, 1, 5, 5) - background = WIDGET_COLOR + layout = GridLayout(2, 1, 5, 0) } - val font = Font("Arial", Font.PLAIN, 11) + val font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) val xpGainedLabel = JLabel( - formatHtmlLabelText("XP Gained: ", primaryColor, "0", secondaryColor) + formatHtmlLabelText("Gained: ", primaryColor, "0", secondaryColor) ).apply { this.horizontalAlignment = JLabel.LEFT this.font = font @@ -177,7 +214,7 @@ object XPTrackerView { return XPWidget( skillId = -1, - panel = widgetPanel, + container = widgetPanel, xpGainedLabel = xpGainedLabel, xpLeftLabel = JLabel(formatHtmlLabelText("XP Left: ", primaryColor, "0", secondaryColor)).apply { this.horizontalAlignment = JLabel.LEFT @@ -193,19 +230,83 @@ object XPTrackerView { } - fun createXPTrackerView(): JPanel? { - val widgetViewPanel = JPanel() - widgetViewPanel.layout = BoxLayout(widgetViewPanel, BoxLayout.Y_AXIS) - widgetViewPanel.background = VIEW_BACKGROUND_COLOR - widgetViewPanel.add(Box.createVerticalStrut(5)) + fun createXPTrackerView(){ + val widgetViewPanel = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + background = VIEW_BACKGROUND_COLOR + } + val popupMenu = createResetMenu() + + // Create a custom MouseListener + val rightClickListener = object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + if (e.isPopupTrigger) { + popupMenu.show(e.component, e.x, e.y) + } + } + + override fun mouseReleased(e: MouseEvent) { + if (e.isPopupTrigger) { + popupMenu.show(e.component, e.x, e.y) + } + } + } + + // Create the XP widget totalXPWidget = createTotalXPWidget() - widgetViewPanel.add(wrappedWidget(totalXPWidget!!.panel)) + val wrapped = wrappedWidget(totalXPWidget!!.container) + addMouseListenerToAll(wrapped,rightClickListener) + wrapped.addMouseListener(rightClickListener) + widgetViewPanel.add(Box.createVerticalStrut(5)) + widgetViewPanel.add(wrapped) widgetViewPanel.add(Box.createVerticalStrut(5)) - return widgetViewPanel + xpTrackerView = widgetViewPanel } + + fun createResetMenu(): JPopupMenu { + // Create a popup menu + val popupMenu = JPopupMenu() + + val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) + + popupMenu.background = Color(45, 45, 45) + + // Create menu items with custom font and colors + val menuItem1 = JMenuItem("Reset Tracker").apply { + font = rFont // Set custom font + background = Color(45, 45, 45) // Dark background for item + foreground = Color(220, 220, 220) // Light text color for item + } + + val menuItem2 = JMenuItem("Option 2").apply { + font = rFont + background = Color(45, 45, 45) + foreground = Color(220, 220, 220) + } + + val menuItem3 = JMenuItem("Option 3").apply { + font = rFont + background = Color(45, 45, 45) + foreground = Color(220, 220, 220) + } + + // Add menu items to the popup menu + popupMenu.add(menuItem1) + //popupMenu.add(menuItem2) + //popupMenu.add(menuItem3) + + // Add action listeners to each menu item (optional) + menuItem1.addActionListener { resetXPTracker(xpTrackerView!!) } + //menuItem2.addActionListener { println("Option 2 selected") } + //menuItem3.addActionListener { println("Option 3 selected") } + + return popupMenu + } + + fun createXPWidget(skillId: Int, previousXp: Int): XPWidget { val widgetPanel = Panel().apply { layout = BorderLayout(5, 5) @@ -242,14 +343,14 @@ object XPTrackerView { } val textPanel = Panel().apply { - layout = GridLayout(2, 2, 5, 5) + layout = GridLayout(2, 2, 5, 0) background = WIDGET_COLOR } - val font = Font("Arial", Font.PLAIN, 11) + val font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) val xpGainedLabel = JLabel( - formatHtmlLabelText("XP Gained: ", primaryColor, "0", secondaryColor) + formatHtmlLabelText("XP Gained: ", primaryColor, "0", secondaryColor) ).apply { this.horizontalAlignment = JLabel.LEFT this.font = font @@ -302,7 +403,7 @@ object XPTrackerView { return XPWidget( skillId = skillId, - panel = widgetPanel, + container = widgetPanel, xpGainedLabel = xpGainedLabel, xpLeftLabel = xpLeftLabel, xpPerHourLabel = xpPerHourLabel, @@ -314,18 +415,18 @@ object XPTrackerView { ) } - fun wrappedWidget(component: Component, padding: Int = 7): Panel { + fun wrappedWidget(component: Component, padding: Int = 7): Container { val outerPanelSize = Dimension( - component.preferredSize.width + 2 * padding, - component.preferredSize.height + 2 * padding + component.preferredSize.width + 2 * padding, + component.preferredSize.height + 2 * padding ) - val outerPanel = Panel(GridBagLayout()).apply { + val outerPanel = JPanel(GridBagLayout()).apply { background = WIDGET_COLOR preferredSize = outerPanelSize maximumSize = outerPanelSize minimumSize = outerPanelSize } - val innerPanel = Panel(BorderLayout()).apply { + val innerPanel = JPanel(BorderLayout()).apply { background = WIDGET_COLOR preferredSize = component.preferredSize maximumSize = component.preferredSize @@ -343,14 +444,14 @@ object XPTrackerView { data class XPWidget( - val panel: Panel, - val skillId: Int, - val xpGainedLabel: JLabel, - val xpLeftLabel: JLabel, - val xpPerHourLabel: JLabel, - val actionsRemainingLabel: JLabel, - val progressBar: ProgressBar, - var totalXpGained: Int = 0, - var startTime: Long = System.currentTimeMillis(), - var previousXp: Int = 0 + val container: Container, + val skillId: Int, + val xpGainedLabel: JLabel, + val xpLeftLabel: JLabel, + val xpPerHourLabel: JLabel, + val actionsRemainingLabel: JLabel, + val progressBar: ProgressBar, + var totalXpGained: Int = 0, + var startTime: Long = System.currentTimeMillis(), + var previousXp: Int = 0 ) \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 65de95e..e8233f9 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -5,22 +5,27 @@ import KondoKit.Helpers.formatHtmlLabelText import KondoKit.Helpers.formatNumber import KondoKit.Helpers.getSpriteId import KondoKit.HiscoresView.createHiscoreSearchView +import KondoKit.HiscoresView.hiScoreView import KondoKit.LootTrackerView.BAG_ICON import KondoKit.LootTrackerView.createLootTrackerView +import KondoKit.LootTrackerView.lootTrackerView import KondoKit.LootTrackerView.npcDeathSnapshots import KondoKit.LootTrackerView.onPostClientTick import KondoKit.LootTrackerView.takeGroundSnapshot import KondoKit.ReflectiveEditorView.addPlugins import KondoKit.ReflectiveEditorView.createReflectiveEditorView +import KondoKit.ReflectiveEditorView.reflectiveEditorView import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite -import KondoKit.XPTrackerView.createTotalXPWidget import KondoKit.XPTrackerView.createXPTrackerView import KondoKit.XPTrackerView.createXPWidget +import KondoKit.XPTrackerView.initialXP +import KondoKit.XPTrackerView.resetXPTracker +import KondoKit.XPTrackerView.totalXPWidget import KondoKit.XPTrackerView.updateWidget import KondoKit.XPTrackerView.wrappedWidget -import KondoKit.plugin.StateManager.initialXP -import KondoKit.plugin.StateManager.totalXPWidget -import KondoKit.plugin.StateManager.xpWidgets +import KondoKit.XPTrackerView.xpTrackerView +import KondoKit.XPTrackerView.xpWidgets +import KondoKit.plugin.StateManager.focusedView import plugin.Plugin import plugin.api.* import plugin.api.API.* @@ -38,37 +43,47 @@ import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import javax.swing.* +@Target(AnnotationTarget.FIELD) +@Retention(AnnotationRetention.RUNTIME) +annotation class Exposed(val description: String = "") class plugin : Plugin() { companion object { - val WIDGET_SIZE = Dimension(270, 55) - val TOTAL_XP_WIDGET_SIZE = Dimension(270, 30) + val WIDGET_SIZE = Dimension(220, 50) + val TOTAL_XP_WIDGET_SIZE = Dimension(220, 30) val IMAGE_SIZE = Dimension(20, 20) - val WIDGET_COLOR = Color(27, 27, 27) - val VIEW_BACKGROUND_COLOR = Color(37, 37, 37) - val primaryColor = Color(129, 129, 129) // Color for "XP Gained:" - val secondaryColor = Color(226, 226, 226) // Color for "0" - var kondoExposed_useLiveGEPrices = true - var kondoExposed_playerXPMultiplier = 5 - const val FIXED_WIDTH = 782 - const val SCROLLPANE_WIDTH = 340 + val WIDGET_COLOR = Color(30, 30, 30) + val VIEW_BACKGROUND_COLOR = Color(40, 40, 40) + val primaryColor = Color(165, 165, 165) // Color for "XP Gained:" + val secondaryColor = Color(255, 255, 255) // Color for "0" + + @Exposed(description = "Default: true, Use Local JSON or the prices from the Live/Stable server API") + var useLiveGEPrices = true + + @Exposed(description = "Used to calculate Combat Actions until next level.") + var playerXPMultiplier = 5 + + @Exposed(description = "Start minimized/collapsed by default") + var launchMinimized = false + + private const val FIXED_WIDTH = 782 + private const val NAVBAR_WIDTH = 30 + private const val MAIN_CONTENT_WIDTH = 242 private const val WRENCH_ICON = 907 - private const val LVL_ICON = 898 private const val LOOT_ICON = 777 private const val MAG_SPRITE = 1423 + const val LVL_ICON = 898 private lateinit var cardLayout: CardLayout - private lateinit var mainContentPanel: Panel - private var scrollPane: JScrollPane? = null - private var hiScoreView: JPanel? = null - private var reflectiveEditorView: JPanel? = null - private var lootTrackerView: JPanel? = null - private var xpTrackerView: JPanel? = null + private lateinit var mainContentPanel: JPanel + private var rightPanelWrapper: JScrollPane? = null private var accumulatedTime = 0L + private var reloadInterfaces = false private const val tickInterval = 600L private var pluginsReloaded = false - private var loginScreen = 160; + private var loginScreen = 160 private var lastLogin = "" private var initialized = false; + private var lastClickTime = 0L } fun allSpritesLoaded() : Boolean { @@ -95,43 +110,36 @@ class plugin : Plugin() { if (lastLogin != "" && lastLogin != Player.usernameInput.toString()) { // if we logged in with a new character // we need to reset the trackers - xpTrackerView?.removeAll() - totalXPWidget = createTotalXPWidget() - xpTrackerView?.add(Box.createVerticalStrut(5)) - xpTrackerView?.add(wrappedWidget(totalXPWidget!!.panel)) - xpTrackerView?.add(Box.createVerticalStrut(5)) - initialXP.clear() - xpWidgets.clear() - - xpTrackerView?.revalidate() - if (StateManager.focusedView == "XP_TRACKER_VIEW") - xpTrackerView?.repaint() + xpTrackerView?.let { resetXPTracker(it) } } lastLogin = Player.usernameInput.toString() } private fun UpdateDisplaySettings() { val mode = GetWindowMode() + val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH when (mode) { WindowMode.FIXED -> { - if (frame.width < FIXED_WIDTH + SCROLLPANE_WIDTH) { - frame.setSize(FIXED_WIDTH + SCROLLPANE_WIDTH, frame.height) + if (frame.width < FIXED_WIDTH + currentScrollPaneWidth) { + frame.setSize(FIXED_WIDTH + currentScrollPaneWidth, frame.height) } - val difference = frame.width - (FIXED_WIDTH + SCROLLPANE_WIDTH) + val difference = frame.width - (FIXED_WIDTH + currentScrollPaneWidth) GameShell.leftMargin = difference / 2 } WindowMode.RESIZABLE -> { - GameShell.canvasWidth -= SCROLLPANE_WIDTH + GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + 16) } } - scrollPane?.revalidate() - scrollPane?.repaint() + rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) + rightPanelWrapper?.revalidate() + rightPanelWrapper?.repaint() } fun OnKondoValueUpdated(){ - StoreData("kondoUseRemoteGE", kondoExposed_useLiveGEPrices) - StoreData("kondoPlayerXPMultiplier", kondoExposed_playerXPMultiplier) + StoreData("kondoUseRemoteGE", useLiveGEPrices) + StoreData("kondoPlayerXPMultiplier", playerXPMultiplier) LootTrackerView.gePriceMap = LootTrackerView.loadGEPrices() + StoreData("kondoLaunchMinimized", launchMinimized) } override fun OnMiniMenuCreate(currentEntries: Array?) { @@ -139,12 +147,16 @@ class plugin : Plugin() { for ((index, entry) in currentEntries.withIndex()) { if (entry.type == MiniMenuType.PLAYER && index == currentEntries.size - 1) { val input = entry.subject - val username = input - .replace(Regex(""), "") - .replace(Regex(""), "") - .split(" ") // Split by spaces - .first() // Take the first part, which is the username - InsertMiniMenuEntry("Lookup", entry.subject, searchHiscore(username.replace(" ","_"))) + // Trim spaces, clean up tags, and remove the level info + val cleanedInput = input + .trim() // Remove any leading/trailing spaces + .replace(Regex(""), "") // Remove color tags + .replace(Regex(""), "") // Remove image tags + .replace(Regex("\\(level: \\d+\\)"), "") // Remove level text e.g. (level: 44) + .trim() // Trim again to remove extra spaces after removing level text + + // Proceed with the full cleaned username + InsertMiniMenuEntry("Lookup", entry.subject, searchHiscore(cleanedInput)) } } } @@ -152,40 +164,31 @@ class plugin : Plugin() { private fun searchHiscore(username: String): Runnable { return Runnable { - cardLayout.show(mainContentPanel, "HISCORE_SEARCH_VIEW") - StateManager.focusedView = "HISCORE_SEARCH_VIEW" + setActiveView("HISCORE_SEARCH_VIEW") val customSearchField = hiScoreView?.let { HiscoresView.CustomSearchField(it) } customSearchField?.searchPlayer(username) ?: run { println("searchView is null or CustomSearchField creation failed.") } - hiScoreView?.repaint() } } - override fun OnPluginsReloaded(): Boolean { if (!initialized) return true UpdateDisplaySettings() - frame.remove(scrollPane) + frame.remove(rightPanelWrapper) frame.layout = BorderLayout() - frame.add(scrollPane, BorderLayout.EAST) - - // Clear or regenerate the reflectiveEditorView - reflectiveEditorView?.removeAll() - reflectiveEditorView?.revalidate() - if(StateManager.focusedView == "REFLECTIVE_EDITOR_VIEW") - reflectiveEditorView?.repaint() + frame.add(rightPanelWrapper, BorderLayout.EAST) frame.revalidate() frame.repaint() pluginsReloaded = true + reloadInterfaces = true return true } - override fun OnXPUpdate(skillId: Int, xp: Int) { if (!initialXP.containsKey(skillId)) { initialXP[skillId] = xp @@ -203,11 +206,11 @@ class plugin : Plugin() { xpWidget = createXPWidget(skillId, previousXp) xpWidgets[skillId] = xpWidget - xpTrackerView?.add(wrappedWidget(xpWidget.panel)) + xpTrackerView?.add(wrappedWidget(xpWidget.container)) xpTrackerView?.add(Box.createVerticalStrut(5)) xpTrackerView?.revalidate() - if(StateManager.focusedView == "XP_TRACKER_VIEW") + if(focusedView == "XP_TRACKER_VIEW") xpTrackerView?.repaint() updateWidget(xpWidget, xp) @@ -221,23 +224,25 @@ class plugin : Plugin() { } if (pluginsReloaded) { - InterfaceList.method3712(true) // Gets the resize working correctly reflectiveEditorView?.let { addPlugins(it) } pluginsReloaded = false } + if (reloadInterfaces){ + InterfaceList.method3712(true) // Gets the resize working correctly + reloadInterfaces = false + } + accumulatedTime += timeDelta if (accumulatedTime >= tickInterval) { lootTrackerView?.let { onPostClientTick(it) } accumulatedTime = 0L } - // Init in the draw call so we know we are between glBegin and glEnd for HD if(!initialized && mainLoadState >= loginScreen) { initKondoUI() } - } private fun initKondoUI(){ @@ -245,25 +250,66 @@ class plugin : Plugin() { if(!allSpritesLoaded()) return; val frame: Frame? = GameShell.frame if (frame != null) { - kondoExposed_useLiveGEPrices = (GetData("kondoUseRemoteGE") as? Boolean) ?: true - kondoExposed_playerXPMultiplier = (GetData("kondoPlayerXPMultiplier") as? Int) ?: 5 - cardLayout = CardLayout() - mainContentPanel = Panel(cardLayout) - mainContentPanel.background = VIEW_BACKGROUND_COLOR - xpTrackerView = createXPTrackerView() - hiScoreView = createHiscoreSearchView() - lootTrackerView = createLootTrackerView() - reflectiveEditorView = createReflectiveEditorView() - mainContentPanel.add(xpTrackerView, "XP_TRACKER_VIEW") - mainContentPanel.add(hiScoreView, "HISCORE_SEARCH_VIEW") - mainContentPanel.add(lootTrackerView, "LOOT_TRACKER_VIEW") - mainContentPanel.add(reflectiveEditorView, "REFLECTIVE_EDITOR_VIEW") + // Disable Font AA + System.setProperty("awt.useSystemAAFontSettings", "off") + System.setProperty("swing.aatext", "false") + + loadFont() + + try { + UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel") + + // Modify the UI properties for a dark theme + UIManager.put("control", Color(50, 50, 50)) // Default background for most controls + UIManager.put("info", Color(50, 50, 50)) + UIManager.put("nimbusBase", Color(35, 35, 35)) // Base color for Nimbus L&F + UIManager.put("nimbusAlertYellow", Color(255, 220, 35)) + UIManager.put("nimbusDisabledText", Color(100, 100, 100)) + UIManager.put("nimbusFocus", Color(115, 164, 209)) + UIManager.put("nimbusGreen", Color(176, 179, 50)) + UIManager.put("nimbusInfoBlue", Color(66, 139, 221)) + UIManager.put("nimbusLightBackground", Color(35, 35, 35)) // Background of text fields, etc. + UIManager.put("nimbusOrange", Color(191, 98, 4)) + UIManager.put("nimbusRed", Color(169, 46, 34)) + UIManager.put("nimbusSelectedText", Color(255, 255, 255)) + UIManager.put("nimbusSelectionBackground", Color(75, 110, 175)) // Selection background + UIManager.put("text", Color(230, 230, 230)) // General text color + + // Update component tree UI to apply the new theme + SwingUtilities.updateComponentTreeUI(GameShell.frame) + } catch (e : Exception) { + e.printStackTrace() + } + + // Restore saved values + useLiveGEPrices = (GetData("kondoUseRemoteGE") as? Boolean) ?: true + playerXPMultiplier = (GetData("kondoPlayerXPMultiplier") as? Int) ?: 5 + launchMinimized = (GetData("kondoLaunchMinimized") as? Boolean) ?: false + + cardLayout = CardLayout() + mainContentPanel = JPanel(cardLayout).apply { + border = BorderFactory.createEmptyBorder(0, 0, 0, 0) // Removes any default border or padding + background = VIEW_BACKGROUND_COLOR + preferredSize = Dimension(MAIN_CONTENT_WIDTH, frame.height) + isOpaque = true + } + + // Register Views + createXPTrackerView() + createHiscoreSearchView() + createLootTrackerView() + createReflectiveEditorView() + + mainContentPanel.add(ScrollablePanel(xpTrackerView!!), "XP_TRACKER_VIEW") + mainContentPanel.add(ScrollablePanel(hiScoreView!!), "HISCORE_SEARCH_VIEW") + mainContentPanel.add(ScrollablePanel(lootTrackerView!!), "LOOT_TRACKER_VIEW") + mainContentPanel.add(ScrollablePanel(reflectiveEditorView!!), "REFLECTIVE_EDITOR_VIEW") val navPanel = Panel().apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) background = WIDGET_COLOR - preferredSize = Dimension(42, frame.height) + preferredSize = Dimension(NAVBAR_WIDTH, frame.height) } navPanel.add(createNavButton(LVL_ICON, "XP_TRACKER_VIEW")) @@ -271,13 +317,13 @@ class plugin : Plugin() { navPanel.add(createNavButton(LOOT_ICON, "LOOT_TRACKER_VIEW")) navPanel.add(createNavButton(WRENCH_ICON, "REFLECTIVE_EDITOR_VIEW")) - val rightPanel = Panel(BorderLayout()).apply { + var rightPanel = Panel(BorderLayout()).apply { add(mainContentPanel, BorderLayout.CENTER) add(navPanel, BorderLayout.EAST) } - scrollPane = JScrollPane(rightPanel).apply { - preferredSize = Dimension(SCROLLPANE_WIDTH, frame.height) + rightPanelWrapper = JScrollPane(rightPanel).apply { + preferredSize = Dimension(NAVBAR_WIDTH + MAIN_CONTENT_WIDTH, frame.height) background = VIEW_BACKGROUND_COLOR border = BorderFactory.createEmptyBorder() // Removes the border completely horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER @@ -285,91 +331,173 @@ class plugin : Plugin() { } frame.layout = BorderLayout() - scrollPane?.let { frame.add(it, BorderLayout.EAST) } + rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) } - frame.revalidate() - frame.repaint() - - StateManager.focusedView = "XP_TRACKER_VIEW" + if(!launchMinimized){ + setActiveView("XP_TRACKER_VIEW") + } else { + setActiveView("HIDDEN") + } initialized = true pluginsReloaded = true - UpdateDisplaySettings() } } override fun Update() { - xpWidgets.values.forEach { xpWidget -> + + val widgets = xpWidgets.values + val totalXP = totalXPWidget + + widgets.forEach { xpWidget -> val elapsedTime = (System.currentTimeMillis() - xpWidget.startTime) / 1000.0 / 60.0 / 60.0 val xpPerHour = if (elapsedTime > 0) (xpWidget.totalXpGained / elapsedTime).toInt() else 0 val formattedXpPerHour = formatNumber(xpPerHour) xpWidget.xpPerHourLabel.text = - formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) - xpWidget.panel.repaint() + formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) + xpWidget.container.repaint() } - totalXPWidget?.let { totalXPWidget -> + totalXP?.let { totalXPWidget -> val elapsedTime = (System.currentTimeMillis() - totalXPWidget.startTime) / 1000.0 / 60.0 / 60.0 val totalXPPerHour = if (elapsedTime > 0) (totalXPWidget.totalXpGained / elapsedTime).toInt() else 0 val formattedTotalXpPerHour = formatNumber(totalXPPerHour) totalXPWidget.xpPerHourLabel.text = - formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) - totalXPWidget.panel.repaint() + formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) + totalXPWidget.container.repaint() } } - override fun OnKillingBlowNPC(npcID: Int, x: Int, z: Int) { val preDeathSnapshot = takeGroundSnapshot(Pair(x,z)) npcDeathSnapshots[npcID] = LootTrackerView.GroundSnapshot(preDeathSnapshot, Pair(x, z), 0) } - - private fun createNavButton(spriteId: Int, viewName: String): JButton { - val bufferedImageSprite = getBufferedImageFromSprite(GetSprite(spriteId)) - val buttonSize = Dimension(42, 42) - val imageSize = Dimension(bufferedImageSprite.width, bufferedImageSprite.height) - - val actionListener = ActionListener { + private fun setActiveView(viewName: String) { + // Handle the visibility of the main content panel + if (viewName == "HIDDEN") { + mainContentPanel.isVisible = false + } else { + if (!mainContentPanel.isVisible) { + mainContentPanel.isVisible = true + } cardLayout.show(mainContentPanel, viewName) - StateManager.focusedView = viewName } + reloadInterfaces = true + UpdateDisplaySettings() + + // Revalidate and repaint necessary panels + mainContentPanel.revalidate() + mainContentPanel.repaint() + rightPanelWrapper?.revalidate() + rightPanelWrapper?.repaint() + frame?.revalidate() + frame?.repaint() + + focusedView = viewName + } + + private fun createNavButton(spriteId: Int, viewName: String): JPanel { + val bufferedImageSprite = getBufferedImageFromSprite(GetSprite(spriteId)) + val buttonSize = Dimension(NAVBAR_WIDTH, 32) + val imageSize = Dimension((bufferedImageSprite.width / 1.2f).toInt(), (bufferedImageSprite.height / 1.2f).toInt()) + val cooldownDuration = 100L + + val actionListener = ActionListener { + val currentTime = System.currentTimeMillis() + if (currentTime - lastClickTime < cooldownDuration) { + return@ActionListener + } + lastClickTime = currentTime + + if (focusedView == viewName) { + setActiveView("HIDDEN") + } else { + setActiveView(viewName) + } + } + + // ImageCanvas with forced size val imageCanvas = ImageCanvas(bufferedImageSprite).apply { background = WIDGET_COLOR preferredSize = imageSize maximumSize = imageSize minimumSize = imageSize - addMouseListener(object : MouseAdapter() { - override fun mouseClicked(e: MouseEvent?) { - actionListener.actionPerformed(null) - } - }) } - val button = JButton().apply { + // Wrapping the ImageCanvas in another JPanel to prevent stretching + val imageCanvasWrapper = JPanel().apply { + layout = GridBagLayout() // Keeps the layout of the wrapped panel minimal + preferredSize = imageSize + maximumSize = imageSize + minimumSize = imageSize + isOpaque = false // No background for the wrapper + add(imageCanvas) // Adding ImageCanvas directly, layout won't stretch it + } + + val panelButton = JPanel().apply { layout = GridBagLayout() preferredSize = buttonSize maximumSize = buttonSize minimumSize = buttonSize background = WIDGET_COLOR - isFocusPainted = false - isBorderPainted = false + isOpaque = true // Ensure background is painted val gbc = GridBagConstraints().apply { anchor = GridBagConstraints.CENTER + fill = GridBagConstraints.NONE // Prevents stretching } - add(imageCanvas, gbc) - addActionListener(actionListener) + add(imageCanvasWrapper, gbc) + + // Hover and click behavior + val hoverListener = object : MouseAdapter() { + override fun mouseEntered(e: MouseEvent?) { + background = WIDGET_COLOR.darker() + imageCanvas.fillColor = WIDGET_COLOR.darker() + imageCanvas.repaint() + repaint() + } + + override fun mouseExited(e: MouseEvent?) { + background = WIDGET_COLOR + imageCanvas.fillColor = WIDGET_COLOR + imageCanvas.repaint() + repaint() + } + + override fun mouseClicked(e: MouseEvent?) { + actionListener.actionPerformed(null) + } + } + + addMouseListener(hoverListener) + imageCanvas.addMouseListener(hoverListener) } - return button + return panelButton + } + + + fun loadFont(): Font? { + val fontStream = plugin::class.java.getResourceAsStream("res/runescape_small.ttf") + return if (fontStream != null) { + try { + val font = Font.createFont(Font.TRUETYPE_FONT, fontStream) + val ge = GraphicsEnvironment.getLocalGraphicsEnvironment() + ge.registerFont(font) // Register the font in the graphics environment + font + } catch (e: Exception) { + e.printStackTrace() + null + } + } else { + println("Font not found!") + null + } } object StateManager { - val initialXP: MutableMap = HashMap() - val xpWidgets: MutableMap = HashMap() - var totalXPWidget: XPWidget? = null var focusedView: String = "" } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.properties b/plugin-playground/src/main/kotlin/KondoKit/plugin.properties index 51c6d2a..629c117 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.properties +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.properties @@ -1,3 +1,3 @@ AUTHOR='downthecrop' DESCRIPTION='A plugin that adds a right-side panel with custom widgets and navigation.' -VERSION=1.1 \ No newline at end of file +VERSION=2.0 \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/KondoKit/item_configs.json b/plugin-playground/src/main/kotlin/KondoKit/res/item_configs.json similarity index 100% rename from plugin-playground/src/main/kotlin/KondoKit/item_configs.json rename to plugin-playground/src/main/kotlin/KondoKit/res/item_configs.json diff --git a/plugin-playground/src/main/kotlin/KondoKit/npc_hitpoints_map.json b/plugin-playground/src/main/kotlin/KondoKit/res/npc_hitpoints_map.json similarity index 100% rename from plugin-playground/src/main/kotlin/KondoKit/npc_hitpoints_map.json rename to plugin-playground/src/main/kotlin/KondoKit/res/npc_hitpoints_map.json diff --git a/plugin-playground/src/main/kotlin/KondoKit/res/runescape_small.ttf b/plugin-playground/src/main/kotlin/KondoKit/res/runescape_small.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4f3d764c2ff0552a1d459d3834b118897ccedf44 GIT binary patch literal 33260 zcmeHQTdd_*S^v)e%yfoMue7vwnpo zv(J>0kgzA;{?_`|cVFLH|Mmaxz30e+h+HjM7G?CoQ%8<1esbR>ksA(z`pokB()oA& z_KDA<{RNSIkDXn6;n{aR`l-Ld_@_lSt~s}|bmn6>?0gnu{|TN)&VjH{E?*Yee?R*7 zom=0&^!ogoZ=nA^k;MPzUDUcZ<8B9If&M^@@ulQaBAVw!f%dl z9=&1og}d+B*#Vs+BYAP*Bt~*)WMSvOcm8GP&v(x6yl>~Hzx`+5{=&E4_>W(bzfp-F zz5VcJ;74`w!#j7cr03l401sVr)yl`Nf5(4g?^0`jvGIxjVZ-oFS(K)rdk{MgB~+#< zI|bWMVi%i`(b=)rH?fPhuYzWgw2&k+M5w>w=z5;K?;|bRm4WRvujl zTi3~h3%~CCH_4k8zGQ7UdvM|J1=9Oo1?h(u{>9r1@?*`d-frZ&<}Kb{l!u!W-rgsN zn~UDwFSj&*Z+ZKW9A5l)Z(k$N z>pD5T?_ZtgCONtPJ=R7nH|+o26PxE>*jhb%ZhQ2R&9!G&SKhz0wYoVv zcJ%1mPCmb}a%y?${L1Lm`qJ9k$(6IuuPtpozPYh|YJ2PXJvZ8XcJ%nECr8R~Zu9);$&Kxmt&OE^=vi7D zy=VRO6X&+K&%gc1k!Rt}1@-3e^5%Lcf;*}$^Zw4!#ia|Q)6cK2ZI3RlZl5#VDtWc* zx_I&8VbuqV)HcyX$0D4$aOA?d&5K8lJ^1KDj~qL(wE_=6xiUJjxxS9E(edr=t<}@d z)9cX(Ha8xC&h?e8fF-S%INso>T@e@X4$351mVM*TW61~tuC)@Tv)kqO-{=5vVpNv zvW(I5XpPWbM|%zbPNIJn9BV51I3zcq^%P(W)Md4>n}%8XM*|BVhP^GhpgwNElLzH6 zyd1aiK*z_)UadmQ2wsoW*Cjav&5UYGo&#+Y85zmr(DJ0>i0d3i&V%x##z|i`AhYfM zFef8<5A>XtCp5p?;C{Ot!M|rcHy1j&IgAW#f_vf|jP95aS10$QJ7Mc0tTT?&$o49% zb4D+swGHd^Km2az00UwV5sQDsV$1rb?%0u!9 zS|^ah70=-((Hd!$t|KcZHdI|V6_|Cxl;9Q-!&F>KL_kVl0NKY_k|chZDAv@(lJJBDgz$KlafILR?ZHt z667i5Yq80pN)jV&iqF;c@)L7--H9W-3y&|uj?x^5x1>e31BYz%d$?4IOwSj@J%+#3 zbXl=#a7#4G5`XBVy-5t+U+;bJu3XuQ;QIifA6- zw_-d>(+KLg(>bo57Bo@|kqgz6K`%a*Eq?2PE7g8xo{)uP8XY56(vb;{{i8e51Rp~Wr#ri6TG0vyPL+ovhGul~u z1@E9l4m)^ApVs%R!AjOlW!JZ$_e{BA?P&C*6FNJ=BKk?%y!EnFBgrO*ca>Keod@1C zUQWDo@(8%!!k;=1eSH`tr@nx7%>&QW$Gt7|-88x0!%x-idR2E;-H{i@&Cz1isG}+c zI>&Szxsw9BT!H-<$dN^LswCRlFVzdDs4jBazFx5ZEeh_i+T|IR!DCj*9X_TQRqdS1 zgzFINTQ%rtL0kE%&l&Qi$CElb1tSUTM5fFSc?o>@8TMNF}n8I z&N>Td!2|V-u~V{xovs`@gFbHlrdkKFU(TF0+Ebgbp&qi2_7&`OMWu>+GtEn+4;&fi zxs03+d}DnKYsdA`%M5-%T$9L&EKp)!)oIs?S-T3QlJuiRSLciLtbkT0=UTatD#}&V zCdbMtw3b^m0(8Hk*`J8OODDgN|X+>J`c@qIyB4Bys0T>-P$JJvh+X zR8DZS(zP9)7PZbRL&Cp;E4IyJ&s&v%w7!6=7Rp#XWaa_$7^66o;bfv>FZ+ON7>o5^kWv0hhc+heJbP%Eu*wu!68>|W39v-$^Z`pS;ecnsCT?mk}y zEm`+7%fHoi^?kVZYuyyc!Lq)9cdg{CIp#aLOJHqrg$4Z@jOQjbR=?fr_m!WU3vv#t zxHC1M(WW<%&A8hLTIC~8Kw`C{58xaUQ%>8NJw%cQShEOI`P&CAl^`uhAFQ z%aq+EP9%t3ZDx*&@ zcC8JMs+SR3V@2r9dt}g^HBvoMhKIU(uj1I?{^xdRnDv5o)d8J7T&$0GqdN|J@FA&R zX@E<=?-fkm3`m{&-5;J&LZJZX25){RV>v6Bqebj~Q}!FHap;CzXkxx}c7THx&jmXB z3`UtZ?t;NJHdnLlCXJ~|>pT_E0HG1{M@rgB4Tu~e=zJv*GVBAZ-FB~!eQs>-v`Pwe zKvXTDO{{&kv-S#htK3F+8CBu*ejQFcIWu#r+i`CPhgQyH)rX2BrIXc!egUK_+_#}m zql6yynSHeD&VaUhR}7CuZrlYt;DjfRu_I*7NYZ>4yxaKj+p)Gj5oaY%C@&MhhlC`_uM%EN_ya0fM4q5gJ-VNI* z`x$h`6XVtozQ8P^tk ztpinBaxXeK#v+Cqb5`kM(mI=H_i{`v1zd*JiuSWx3A|qr_uzhKV&0h@)#jLO?E`7M zIEFT^{LWs2{uJAh&v+(x>-0Q^y*eAvs;>cNu5_-m)>&5DMLp#^xI1~#zS6*_*Wskk z8@uZh5~0a*(0~FRaYYtc1P81&v37d-8|E$cY|u0G;N2p^yY=aZz$fbK`T=6)D9Vw* zYAtz**zTKiLyzJ!mYy$Bh>Tc)QfSxuLR-$cABwBOTCZ z=Emcn2l$#8d#cIFQ7w*pHjBlvQyPpi9>yIQ5hc#H$2NSXogo6yEF`q~$_h#Kpdxg% zsCBeOpE1Et=4#AOaw!1yd?da4sT>6qP#KxlQFjjP4twGpsCSU9)sxW%C_SmKlOiY> zG03!vc5)26IFY1A5YKMUT_8y*zNk&x$#A!?{(!Dl^gZS;azbv*es&*{W2`0mQs;_S zq={M3TFA6uIMEcTTA7TxaBFP&pCN_&jig)P^_#iuV24 zB&b|tH7fe#ekrayQ*x@!54FYqQf2GTl3j=6q0V+5BL8{<$;fk3|Gf4Z#>qWw${kLP zIqVftpJN7G8?$YClVi8DBMk(Y8_o|v_b=>Cw5w5(Um=rI??wEKRBK}Dv(zdZIvm#- z3OaTJ^P-Q@14mSmVqfcOyZ2l6c8 zqw}w^V!E`3piT7y*ELq0mOTdeiBW*#Jm_m(A(rg(JMBIzL4(6&TcLMie0~p6^JUjL ze#&@nzoKGC9pbPZ)mnWBpR)NkcV0A_PTdUq$@4d)M_236@5s|AgZ#IThDq z*F3Ii%3VM66bFlxQYi2S&FF`I#T*0FT2U@gEHgfee(p-6Z+j)@an94NT1l|vpnca* znpSic_e66Gs@IQIG)8%?RBn2Ran)ka#Y-ca7oPI@dE(f-#o8TW>LG9qsm=_&4lzbM zy$CQqV=T4Ykjjh(8jET#xE^C%0rY5x1+`o#U+bvN^lqHSZIvTF@Icir2pBYtX3!ugf@eaq|h`m&e#g?(z$SL#Gsy8dDm zV+x=X*I3Y2I*{uD1*6HivW^y)NIGJi;By|WZ__wd!N^O4(?c_5KTz$^)P%jzY2VjP zjqL~V`LWdqzq32{3eerB*b3ljkrwM}Kv!oHG>yeEX%#@5`xEr=K6z%6&9c@zpSAfo z?qjL7T?IqAct+I5&u_uah&iH)3g>K)rmu|I1877EZ2;Th4SXcEfTkGZz+LD(bwR!2 z3X*+3V_v3u7B&ON3`Adjp|xxlvHznN-UF*IGx~Zz$ZzfQ%IdoxH9#G64842@AOn1^ zg&9GOE*h_nW#uGC5q|$U@yS=y)?GX~e%ap?XVpdgY`a&6z0W*!=c@Zzo8}1Pl-qMf zX0=uz4Pc}WPPcEc?V&=E%LcjBI?%jRKRs+xwZ!uVYQ9q|F+=q-r7&n`4Okai6=&uuS8 zGB|i0#LC0GO~3aBU$@4=UqFGdXC5`9eLE9cjZxccZPgBE+55@mfz{vQeaGQDcLmyU zo{S#yZ8HZtMtBDk>yz}5a7i;<+-xYtb21eB`;G`nO{8>#lJ z57lb3G^|6fz^Er;-2qhxb{O27V+OkGZdMHyW12?R88#X{4V+3@_PK9{7B?+N=)0P5I50^HF zl_!~BaYd#`PsaQHeG$SO2tT~`ILk7?AMlk`9)bm+4zmC;<{ITG?A$VcpF z_Wk-R&I#8OJ)-}Uu1euKah*-)uUCJFs}9F?rDdh#oip62KjrS^X}5l&_Lg5)yvnFY z{J#lOr$(-?HSz#{l=>F@!1A5=x#fg?e?p1OB*Bhaor(**%+8Zq%;+_@xkKx;H98Dw z4vXPhciyk^xt|O4QZF~EWtUo0o;IIuu~c2VkK281?wk#F|Kx^|@Rd51lfz>e+sTM?X$jJ=bX|C#V}_|s~X)pmejKKogSwGK9lv)>`?)uK9l>U zQk_f(J@606?^>1gA0EDJzvFwc{e0g$-zuw_E$}2EU%<1nUiX>chZwK)R~$uHjal&T z#^AoFjmNGtyH=2G7;{HN&yz#;$bpqs@tif4EqBOXXksgwR>wc6`hr!Bp*Y_Ay2$Vw zps{40LomC!&c|M!E+uFo6vMNsi(`6b1Rhq|-m1&6rcaeRKl=b7$v`#V0KGv-|r z#q8kS>}6np+G9Hb9M_WtNL{+l33wor{5`NyIg%rq;L+Uhyk)$BllS#mpMIZX`lkz! z4Bu4B`&yv|o?uwVc^47-Yh)3jem^Ct-}Bl8H|RQDTKxz$W#k2{u79n++O_ zOSv-I1oRDKG-=#z#c3UfB*21dDBBU~&XT*I%&u-NRCblE9 zSmA{yvwByObQHAt^l3FfpT08Qr|a9Nqf-5w^r>e851?wz-Ukh_jcbqS!|Sg+-2-NPFNfEwuIIWB6{FS41&`Jb>4g&Q^Hba}kP4bs1=^gU?z~HTJ>YN0 z=lxYNG--@Lic{z0iMIL!%+>2X_<_1m8iAGb4KKE)-x+w z%4RJpdun#VLZU>cx`QslwFb+L?fo~-`CIa2_9Nn0)zMe~z@qgG%XL*2w37nfaYoWe z;{R&Va~1|&TjG9JBQ4l7xZ5Vvs($C{_imq6XVX;k1a0&!{0(~K6IPRQATzYvR+H^z z)sOVb`U4Lw1AF(UU*mCCzx&RCcq1FSHVZsR26gAi-Y1>y);mxxmrk}Y*qb$s>!{)W zKL2v(5Vpco#jRI)(i}F*9aW(C%J$o0c3HJu`!!oJo_rk0vZmK-UbQjO@gs3mwHdB) zR6e+lYg1|x_KO+&mad<~8Ijfo+G;EJZ0NXM2l3nHL`$snuth#q!NV*4>HPr$x^{Sm)=K+-(3dUb?e``I$nEGGbw)?V2e{F3H^LzK~vq=B> z&OBMxY$x{^xMu%Kycdr+Ikw;BjmI$mT{%6YSH&>iHMg-^bu2lJxC3=Qf>vBpHaypS zg!SaI(f>i#)0OyN#{7-Bh;v8#NzBY^RD0T`#;#WMrq4yeSi-zz!&Nr=;a@h5bInES zT1Q2+eT}UVoD$+Z7vJ5PGd6sxPS0BJ>ZeP!@-Wt|I`Ve=y3d9@u}6kh()tZ=oeo*h z18Bv;$2-xPJg(h5zj=)IjB84CH4Ye1>lqlJ7T8VzzOsA9k))i&MkOu#6@ygvyL)K+ z$;A{ed@q7F)dEB*ZTf_sezhbdT!q1U9Fdy z-WIQw@OBaMsNII=wcWoDk(3(}em+dDEwDh#9QvyFV7BU*s&5}T@STb9@5-L9L5Y61 zFIjE|UWdJs{#E^ECsw)IpD>R6L88t)rHg7Q zPH)GJul2LLN45W_->mwCa@9&)U?r<%rD;x*(W0%`YsF6O@RKtUK7}tywPLK|u5a@` z2g%T#Oovt#+L1j_O*d#(ac(Jjwsy--;*yz3{dA zzb?;O`}{_yC;)|5Lz>dF@pX8TN+jhjChdDiidp3tCB}c_*Q=e09;%K^SuqdM4tmARE@~u)SLrR0>&0 zo~`d+E|PgN)r0UXJkT=~pQzLtnCE{su^4ML)H(!R_Xv)sPPL%R8PbUDoudV{QOJc8 zB(P=@_;PB(yX5%+fj;W}#+0YytTS@=o_A%?0O6D3Vme_H+5pv=gNk5{REXyy9-h(o)6It1+zEwR1=7g$CcIktK2V9X9iID5XDO-sRjCMB|X z-y}7UpaJVT>)Z>^|H+W+WL?B}D>;+uwPSi)R~*_pt{%~Y@YpI0eb6dBYr8m4@W#0^ zH^Xb`#C<8AMo_bAf>!k}c^^poWzbJf&+c0p)My^~HSBX!O_+CS((u>OIzQB30FFIJ z1B%WPIa*y)R+f61!AVFRK;N%1mRXIbXSLW2Ra@Tg*t{JM%y?;LAl0**`hC?7o-T$Q zD3g5goEvun5BM}gfp^VEH^(74(Nf+mW9o5+5BeP!ozK1f9S!4=qmnBUSo|E?Yn>5W|5z9Oli{9E7>|CJPkkyT%XUO%-19^i zdFyG)kOxFQ6}L5U`|Nt1R2wsEq*(m0m|%Ab^!%el2QUMeMX#N`&jl<}8!cC@8GS%6 z1Ei%6pg$aEKXf1u;6^VSwySMV1ID92=0RySg+|wBpIPS`FYo<-a+f)ovA^gL98nJj zR&{3}E&2Ea91#q0H=^)7A_-h`G{}{BfBu|Jvk;bIykh-79(p;nQ{R>UJs9MM+Ie3@ zTtDe6-gg|kavjg(xutyd6m88V_>`UpBdOmX%c+mUUTA#yNA5_E_9WaL$7wVzq(y0l=jZqvN;A)T!);o9 zE%3&n?iuh%t!BfOUaVgu@%~F0bhaIa=LGO4i_x+75iKN8Yq>v;92>p#=@PHcpwWe| zqW^!Gqc7l~_ae&dYj`m954?~8o&tb&)op+?fX@TI4#3}~Kac>BJNN|Pd-!5G_+Is0 z`~kZ)kwf7w?B4w!_D|}rjWZ4`fn^Euf7j}u~&al ziAmzyDb^LIpEa|7Vh!ardrx4@rUz9Dk!CH$Fs&~JlZuiXbY2LSKuJ|lAb zGXTin0bO_eApo}Td^6zl0Px@WpCUiD4M6*@I{;|k^&cW5=)C(N;6s4V0Kj(-^xlK^ zy`bOwKEM}6?zYh{{-kKKsy0jkHP+9FN*y1QvmQh{ Date: Tue, 8 Oct 2024 01:23:00 -0700 Subject: [PATCH 02/47] XP Drop 1.3 --- .../src/main/kotlin/XPDropPlugin/plugin.kt | 197 ++++++++++++++---- .../kotlin/XPDropPlugin/plugin.properties | 2 +- .../main/kotlin/XPDropPlugin/res/rl-lvls.png | Bin 0 -> 348 bytes .../main/kotlin/XPDropPlugin/res/xpIco.png | Bin 0 -> 329 bytes 4 files changed, 158 insertions(+), 41 deletions(-) create mode 100644 plugin-playground/src/main/kotlin/XPDropPlugin/res/rl-lvls.png create mode 100644 plugin-playground/src/main/kotlin/XPDropPlugin/res/xpIco.png diff --git a/plugin-playground/src/main/kotlin/XPDropPlugin/plugin.kt b/plugin-playground/src/main/kotlin/XPDropPlugin/plugin.kt index 24f1feb..e857ef1 100644 --- a/plugin-playground/src/main/kotlin/XPDropPlugin/plugin.kt +++ b/plugin-playground/src/main/kotlin/XPDropPlugin/plugin.kt @@ -1,12 +1,34 @@ -package XPDropPlugin; - +package XPDropPlugin + +import KondoKit.Exposed import plugin.Plugin -import plugin.annotations.PluginMeta -import plugin.api.* +import plugin.api.API +import plugin.api.API.* +import plugin.api.FontColor.fromColor +import plugin.api.FontType +import plugin.api.TextModifier +import plugin.api.WindowMode +import rt4.Sprite +import rt4.client import java.awt.Color +import java.awt.image.BufferedImage +import java.io.InputStream +import javax.imageio.ImageIO import kotlin.math.ceil + class plugin : Plugin() { + + enum class Theme { + DEFAULT, RUNELITE + } + + @Exposed + private var theme = Theme.DEFAULT + + @Exposed + private var alwaysShow = false + private val displayTimeout = 10000L // 10 seconds private val drawStart = 175 private val drawPadding = 25 @@ -15,41 +37,50 @@ class plugin : Plugin() { private var totalXp = 0 private val activeGains = ArrayList() private var lastGain = 0L + private val IN_GAME = 30 + + private val spriteCache = HashMap() + + override fun Init() { + val themeIndex = (GetData("xp-drop-theme") as? String) ?: "DEFAULT" + theme = Theme.valueOf(themeIndex) + alwaysShow = (GetData("xp-drop-alwaysShow") as? Boolean) ?: false + } override fun Draw(deltaTime: Long) { - if (System.currentTimeMillis() - lastGain >= displayTimeout && activeGains.isEmpty()) - return + if (shouldSkipDrawing()) return drawTotalXPBox() - val removeList = ArrayList() - var posX = API.GetWindowDimensions().width / 2 - if (API.GetWindowMode() == WindowMode.FIXED) - posX += 60 + val movementSpeedFactor = deltaTime / 16.666 // 60 FPS - for(gain in activeGains) { - gain.currentPos -= ceil(deltaTime / 20.0).toInt() + for (gain in activeGains) { + gain.currentPos -= ceil(movementSpeedFactor).toInt() // Adjust movement based on deltaTime if (gain.currentPos <= drawClear) { removeList.add(gain) totalXp += gain.xp - } else if (gain.currentPos <= drawStart){ - val sprite = XPSprites.getSpriteForSkill(skillId = gain.skill) - sprite?.render(posX - 25, gain.currentPos - 20) - API.DrawText( - FontType.SMALL, - FontColor.fromColor(Color.WHITE), - TextModifier.LEFT, - addCommas(gain.xp.toString()), - posX, - gain.currentPos - ) + } else if (gain.currentPos <= drawStart) { + drawXPDrops(gain) } } activeGains.removeAll(removeList.toSet()) } + private fun shouldSkipDrawing(): Boolean { + return client.gameState < IN_GAME || (!alwaysShow && isDisplayTimeoutExpired() && activeGains.isEmpty()) + } + + fun OnKondoValueUpdated() { + StoreData("xp-drop-theme",theme.toString()) + StoreData("xp-drop-alwaysShow",alwaysShow) + } + + private fun isDisplayTimeoutExpired(): Boolean { + return System.currentTimeMillis() - lastGain >= displayTimeout + } + override fun OnXPUpdate(skill: Int, xp: Int) { if (xp == lastXp[skill]) return @@ -81,6 +112,54 @@ class plugin : Plugin() { } private fun drawTotalXPBox() { + when (theme) { + Theme.DEFAULT -> drawDefaultXPBox() + Theme.RUNELITE -> drawRuneliteXPBox() + } + } + + private fun drawXPDrops(gain : XPGain) { + when (theme) { + Theme.DEFAULT -> drawDefaultXPDrop(gain) + Theme.RUNELITE -> drawRuneliteXPDrops(gain) + } + } + + private fun drawDefaultXPDrop(gain: XPGain) { + var posX = API.GetWindowDimensions().width / 2 + if (API.GetWindowMode() == WindowMode.FIXED) + posX += 60 + val sprite = spriteCache.getOrPut(gain.skill) { XPSprites.getSpriteForSkill(skillId = gain.skill) } + sprite?.render(posX - 25, gain.currentPos - 20) + DrawText( + FontType.SMALL, + fromColor(Color.WHITE), + TextModifier.LEFT, + addCommas(gain.xp.toString()), + posX, + gain.currentPos + ) + } + + private fun drawRuneliteXPDrops(gain: XPGain) { + val w = API.GetWindowDimensions().width + val offset = if(API.GetWindowMode() == WindowMode.FIXED) 251 else 225 + val extra = 2; + val posX = w - (offset + extra) + + val str = addCommas(gain.xp.toString()) + val fontCharWidth = 4 + val displace = str.length*fontCharWidth + 30 + + // should be scaled https://github.com/runelite/runelite/blob/0500906f8de9cd20875c168a7a59e5e066ed5058/runelite-client/src/main/java/net/runelite/client/game/SkillIconManager.java#L50 + // but for now this is good enough + + val sprite = spriteCache.getOrPut(gain.skill) { XPSprites.getSpriteForSkill(skillId = gain.skill) } + sprite?.render(posX - displace, gain.currentPos - 20) + drawTextWithDropShadow(posX, gain.currentPos, Color.WHITE, addCommas(gain.xp.toString())) + } + + private fun drawDefaultXPBox() { var posX = API.GetWindowDimensions().width / 2 val posY = API.GetWindowDimensions().height / 4 @@ -89,13 +168,13 @@ class plugin : Plugin() { API.ClipRect(0, 0, posX * 2, posY * 4) - val horizontal = API.GetSprite(822) - val horizontalTop = API.GetSprite(820) - val tlCorner = API.GetSprite(824) - val blCorner = API.GetSprite(826) - val trCorner = API.GetSprite(825) - val brCorner = API.GetSprite(827) - val bg = API.GetSprite(657) + val horizontal = spriteCache.getOrPut(822) { API.GetSprite(822) } + val horizontalTop = spriteCache.getOrPut(820) { API.GetSprite(820) } + val tlCorner = spriteCache.getOrPut(824) { API.GetSprite(824) } + val blCorner = spriteCache.getOrPut(826) { API.GetSprite(826) } + val trCorner = spriteCache.getOrPut(825) { API.GetSprite(825) } + val brCorner = spriteCache.getOrPut(827) { API.GetSprite(827) } + val bg = spriteCache.getOrPut(657) { API.GetSprite(657) } bg?.render(posX - 77, 10) API.FillRect(posX - 75, 5, 140, 30, 0, 64) @@ -112,26 +191,58 @@ class plugin : Plugin() { horizontalTop?.render(posX + 9, -8) horizontal?.render(posX + 9, 22) - API.DrawText( - FontType.SMALL, - FontColor.fromColor(Color.WHITE), - TextModifier.LEFT, - "Total Xp: ${addCommas(totalXp.toString())}", - posX - 65, - 28 + DrawText( + FontType.SMALL, + fromColor(Color.WHITE), + TextModifier.LEFT, + "Total Xp: ${addCommas(totalXp.toString())}", + posX - 65, + 28 ) } + private fun drawRuneliteXPBox() { + val boxHeight = 29 + val boxWidth = 119 + val posX = API.GetWindowDimensions().width + + val innerBorderColor = Color(90, 82, 69).rgb + val outerBorderColor = Color(56,48,35).rgb + + val offset = if(API.GetWindowMode() == WindowMode.FIXED) 251 else 225 + val boxStart = posX - (offset + boxWidth) + val yOffset = if(API.GetWindowMode() == WindowMode.FIXED) 4 else 0 + + val lvlIcon = 898; + val sprite = spriteCache.getOrPut(lvlIcon){ + val imageStream: InputStream = plugin::class.java.getResourceAsStream("res/rl-lvls.png") + imageStream.use { imageStream -> + val image: BufferedImage = ImageIO.read(imageStream) + API.GetSpriteFromPNG(image) + } + } + + // Draw a simple rectangle instead of the default box design + API.FillRect(boxStart, yOffset, boxWidth, boxHeight, innerBorderColor, 150) + drawTextWithDropShadow(boxStart+boxWidth-4, 18+yOffset, Color.WHITE, addCommas(totalXp.toString())) + + // Inner Border + API.DrawRect(boxStart+1, 1+yOffset, boxWidth-2, boxHeight-2, innerBorderColor) + // redraw around the border + API.DrawRect(boxStart, yOffset, boxWidth, boxHeight, outerBorderColor) + sprite?.render(boxStart + 3, 3+yOffset) + } + data class XPGain(val skill: Int, val xp: Int, var currentPos: Int) - fun addCommas(num: String): String{ + fun addCommas(num: String): String { var newString = "" - if(num.length > 9){ + if (num.length > 9) { return "Lots!" } var counter = 1 num.reversed().forEach { - if(counter % 3 == 0 && counter != num.length){ + if (counter % 3 == 0 && counter != num.length) { newString += "$it," } else { newString += it @@ -140,4 +251,10 @@ class plugin : Plugin() { } return newString.reversed() } + + private fun drawTextWithDropShadow(x: Int, y: Int, color: Color, text: String, mod : TextModifier = TextModifier.RIGHT) { + DrawText(FontType.SMALL, fromColor(Color(0)), mod, text, x + 1, y + 1) + DrawText(FontType.SMALL, fromColor(color), mod, text, x, y) + } } + diff --git a/plugin-playground/src/main/kotlin/XPDropPlugin/plugin.properties b/plugin-playground/src/main/kotlin/XPDropPlugin/plugin.properties index 35027ea..53b820f 100644 --- a/plugin-playground/src/main/kotlin/XPDropPlugin/plugin.properties +++ b/plugin-playground/src/main/kotlin/XPDropPlugin/plugin.properties @@ -1,3 +1,3 @@ AUTHOR='Ceikry' DESCRIPTION='Draws nice and clean experience drops onto the screen.' -VERSION=1.2 +VERSION=1.3 diff --git a/plugin-playground/src/main/kotlin/XPDropPlugin/res/rl-lvls.png b/plugin-playground/src/main/kotlin/XPDropPlugin/res/rl-lvls.png new file mode 100644 index 0000000000000000000000000000000000000000..c840a495ce16b88320692178ba99e69ae0487456 GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6M!3-p2R(v-HQjEnx?oNz1PwLbIIh+L^k;M!Q zd`Cc-ajG_-G*Hk!z$e5Ns1V5H=H@P%SFvNq4tWl)l`Cck^o1E$SWTMPb0{ogvz3Wt zjNBw;O+EYBZb8cwHQZ|Q<19_AR27t!xm71_Ss(+{FIp1h7yO^$KPI?W{uAW9sh%#5 zAr*64FJ9z3q`<>^Ax@$@*yP`Tb3MbtiINu;b@}GJc*6MN;W9-AroC-BPI_tV`39{w z&+gsO#(&yoR!C^xj-UR=-_Bm`a5QwnTl>yBp^D)lcH%`D_>$ Xx<{DEuRW~}bRdJLtDnm{r-UW|O6`vG literal 0 HcmV?d00001 diff --git a/plugin-playground/src/main/kotlin/XPDropPlugin/res/xpIco.png b/plugin-playground/src/main/kotlin/XPDropPlugin/res/xpIco.png new file mode 100644 index 0000000000000000000000000000000000000000..c68a872452810c0c17a7b50a7572bf256806fe48 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&j3?%D+y-WjAjKx9jPK-BC>eK@{oCO|{#S9F5 zM?jcysx}`;xln*lh%1mb(w2-3@$z!Ec>iQWX{xyYEKxO}C|gO8UogXe5U8qr@DC`m z&(p;*q+(9&#fyT?3OsBN?0@yOFjgI6u>F32;k@U&lh{`Tuxs$%h^zi^gk7=4;Y4$z z$mfOt0&&x))u#_+9ALle^B>@BhFyd2vb4^UrfZ PVZ-3*>gTe~DWM4f9sGa1 literal 0 HcmV?d00001 From 8076568083bc4dbb0e6953cb2c3db298ddfa4139 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Tue, 8 Oct 2024 01:23:57 -0700 Subject: [PATCH 03/47] ResizableSD 1.1 --- .../main/kotlin/ToggleResizableSD/plugin.kt | 76 ++++++++++--------- .../ToggleResizableSD/plugin.properties | 2 +- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.kt b/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.kt index 1eb5198..2ce17cd 100644 --- a/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.kt +++ b/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.kt @@ -1,84 +1,90 @@ package ToggleResizableSD +import KondoKit.Exposed import plugin.Plugin -import plugin.annotations.PluginMeta import plugin.api.API -import rt4.* +import plugin.api.API.StoreData +import rt4.DisplayMode +import rt4.GameShell +import rt4.InterfaceList +import rt4.client import java.awt.event.KeyAdapter import java.awt.event.KeyEvent class plugin : Plugin() { - var toggleResize = false - var wantHd = false //Setting wantHd to true hides the black screen on logout (when resize SD is enabled), by enabling HD on logout + + @Exposed("Use Resizable SD") + var useResizable = false + + @Exposed("Setting wantHd to true hides the black screen on logout (when resize SD is enabled), by enabling HD on logout ") + var wantHd = false + override fun Init() { API.AddKeyboardListener(object : KeyAdapter() { override fun keyPressed(e: KeyEvent) { if (e.keyCode == KeyEvent.VK_F12) { - toggleResize = true + toggleResizableSd() } } }) - if (!DisplayMode.resizableSD && API.GetData("use-resizable-sd") == true) { - toggleResize = true + + useResizable = DisplayMode.resizableSD + if (API.GetData("use-resizable-sd") == true) { + useResizable = true } - var osNameLowerCase: String = "" - var osName: String - - try { - osName = System.getProperty("os.name") - } catch (e: Exception) { - osName = "Unknown" - } - - osNameLowerCase = osName.toLowerCase() + + var osNameLowerCase: String = System.getProperty("os.name").toLowerCase() if (!osNameLowerCase.startsWith("mac")) { wantHd = true } + if (API.GetData("want-hd") == false) { wantHd = false } } - + override fun ProcessCommand(commandStr: String, args: Array?) { - when(commandStr.toLowerCase()) { + when (commandStr.toLowerCase()) { "::toggleresizablesd", "::resizablesd", "::togglersd", "::rsd" -> { - toggleResize = true //We could call toggleResizableSd() directly here, but it's not necessary. + toggleResizableSd() } - "::toggleresizablesdhd", "::resizablesdhd", "::togglersdhd", "::rsdhd", -> { + "::toggleresizablesdhd", "::resizablesdhd", "::togglersdhd", "::rsdhd" -> { wantHd = !wantHd - API.StoreData("want-hd", wantHd) + StoreData("want-hd", wantHd) API.SendMessage("You have turned login screen HD " + (if (wantHd) "on" else "off")) } } } - + fun toggleResizableSd() { - //We only want to toggle resizable SD when we are logged in and the lobby/welcome interface is not open. if (InterfaceList.aClass13_26 == null || client.gameState != 30) { return } - toggleResize = false - DisplayMode.resizableSD = !DisplayMode.resizableSD; - if(!DisplayMode.resizableSD){ - //Revert to fixed - API.StoreData("use-resizable-sd", false) //Note: It is important to call StoreData before setWindowMode because setWindowMode causes all plugins to reload. + + DisplayMode.resizableSD = !DisplayMode.resizableSD + useResizable = DisplayMode.resizableSD + StoreData("use-resizable-sd", useResizable) + + if (!DisplayMode.resizableSD) { DisplayMode.setWindowMode(true, 0, -1, -1) } else { - //Use resizable - API.StoreData("use-resizable-sd", true) //Note: It is important to call StoreData before setWindowMode because setWindowMode causes all plugins to reload. DisplayMode.setWindowMode(true, 0, GameShell.frameWidth, GameShell.frameHeight) } } - + override fun Draw(timeDelta: Long) { - if (toggleResize) { + if (useResizable != DisplayMode.resizableSD) { toggleResizableSd() } } - + + fun OnKondoValueUpdated() { + StoreData("want-hd", wantHd) + StoreData("use-resizable-sd", useResizable) + } + override fun OnLogout() { if (DisplayMode.resizableSD && wantHd) { - //Because resizable SD always uses the "HD" size canvas/window mode (check the in-game Graphics Options with resizeable SD enabled if you don't believe me!), useHD becomes true when logging out, so logging out with resizeSD enabled means "HD" will always be enabled on the login screen after logging out, so we might as well fix the HD flyover by setting resizableSD to false first, and then calling setWindowMode to replace the canvas and set newMode to 2. DisplayMode.resizableSD = false DisplayMode.setWindowMode(true, 2, GameShell.frameWidth, GameShell.frameHeight) } diff --git a/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.properties b/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.properties index 08a1c2b..54fa4cc 100644 --- a/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.properties +++ b/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.properties @@ -1,3 +1,3 @@ AUTHOR='ipkpjersi' DESCRIPTION='Allows you to use F12 to toggle resizable SD.' -VERSION=1.0 \ No newline at end of file +VERSION=1.1 \ No newline at end of file From 310c88600a5d4a2102b20fb9949f7c5791c289cc Mon Sep 17 00:00:00 2001 From: downthecrop Date: Tue, 8 Oct 2024 01:25:53 -0700 Subject: [PATCH 04/47] GroundItems 1.3 --- .../src/main/kotlin/GroundItems/plugin.kt | 133 +++++++++--------- .../main/kotlin/GroundItems/plugin.properties | 2 +- .../GroundItems/{ => res}/item_configs.json | 0 3 files changed, 67 insertions(+), 68 deletions(-) rename plugin-playground/src/main/kotlin/GroundItems/{ => res}/item_configs.json (100%) diff --git a/plugin-playground/src/main/kotlin/GroundItems/plugin.kt b/plugin-playground/src/main/kotlin/GroundItems/plugin.kt index ecd5ba8..8fe5b18 100644 --- a/plugin-playground/src/main/kotlin/GroundItems/plugin.kt +++ b/plugin-playground/src/main/kotlin/GroundItems/plugin.kt @@ -1,7 +1,7 @@ package GroundItems +import KondoKit.Exposed import plugin.Plugin -import plugin.annotations.PluginMeta import plugin.api.API.* import plugin.api.FontColor.fromColor import plugin.api.FontType @@ -18,27 +18,26 @@ import java.nio.charset.StandardCharsets import java.text.DecimalFormat import kotlin.math.roundToInt -@PluginMeta( - author = "downthecrop", - description = - """ - Ground Items Overlay. Just like Runelite! - cmds ::set(low,med,high,insane,hide), ::(tag,ignore)item ID, ::(reset)groundconfig - Special thanks to Chisato for the original skeleton. - """, - version = 1.2 -) -open class plugin : Plugin() { +class plugin : Plugin() { + + @Exposed(description = "Default: true, Use Local JSON or the prices from the Live/Stable server API") + private var useLiveGEPrices = true + @Exposed( "Default: 5,000 (blue)") + private var lowValue = 5000 + @Exposed( "Default: 20,000 (green)") + private var mediumValue = 20000 + @Exposed( "Default: 50,000 (orange)") + private var highValue = 50000 + @Exposed( "Default: 100,000 (pink)") + private var insaneValue = 100000 + @Exposed("Default: 0, No labels will be drawn for items below this value (unless tagged)") + private var hideBelowValue = 0 + @Exposed("Tag Items (purple) add/remove with Ctrl+RightClick Tag/Ignore") + private lateinit var taggedItems: List + @Exposed("Ignore items add/remove with Ctrl+RightClick Tag/Ignore") + private lateinit var ignoredItems: List - private var kondoExposed_lowValue = 5000 - private var kondoExposed_mediumValue = 20000 - private var kondoExposed_highValue = 50000 - private var kondoExposed_insaneValue = 100000 - private var kondoExposed_hideBelowValue = 0 - private var kondoExposed_useLiveGEPrices = true private val coindId = 995 - private lateinit var kondoExposed_taggedItems: List - private lateinit var kondoExposed_ignoredItems: List private var gePriceMap = loadGEPrices() @@ -60,23 +59,23 @@ open class plugin : Plugin() { ) override fun Init() { - kondoExposed_lowValue = GetData("low-value") as? Int ?: 5000 - kondoExposed_mediumValue = GetData("medium-value") as? Int ?: 20000 - kondoExposed_highValue = GetData("high-value") as? Int ?: 50000 - kondoExposed_insaneValue = GetData("insane-value") as? Int ?: 100000 - kondoExposed_hideBelowValue = GetData("hide-below-value") as? Int ?: 0 - kondoExposed_useLiveGEPrices = GetData("ground-item-use-remote") as? Boolean ?: true - kondoExposed_taggedItems = GetData("ground-item-tags")?.let { it.toString().split(",").mapNotNull { it.toIntOrNull() } } ?: emptyList() - kondoExposed_ignoredItems = GetData("ground-item-ignore")?.let { it.toString().split(",").mapNotNull { it.toIntOrNull() } } ?: emptyList() - if (gePriceMap.isEmpty()) SendMessage("Ground Items unable to load GE Prices, Remote: $kondoExposed_useLiveGEPrices") + lowValue = GetData("low-value") as? Int ?: 5000 + mediumValue = GetData("medium-value") as? Int ?: 20000 + highValue = GetData("high-value") as? Int ?: 50000 + insaneValue = GetData("insane-value") as? Int ?: 100000 + hideBelowValue = GetData("hide-below-value") as? Int ?: 0 + useLiveGEPrices = GetData("ground-item-use-remote") as? Boolean ?: true + taggedItems = GetData("ground-item-tags")?.let { it.toString().split(",").mapNotNull { it.toIntOrNull() } } ?: emptyList() + ignoredItems = GetData("ground-item-ignore")?.let { it.toString().split(",").mapNotNull { it.toIntOrNull() } } ?: emptyList() + if (gePriceMap.isEmpty()) SendMessage("Ground Items unable to load GE Prices, Remote: $useLiveGEPrices") } private fun isTagged(itemId: Int): Boolean { - return kondoExposed_taggedItems.contains(itemId) + return taggedItems.contains(itemId) } private fun isHidden(itemId: Int): Boolean { - return kondoExposed_ignoredItems.contains(itemId) + return ignoredItems.contains(itemId) } override fun Draw(timeDelta: Long) = renderGroundItemNames() @@ -141,10 +140,10 @@ open class plugin : Plugin() { val screenY = screenPos[1] val color = when { isTagged(itemDef.id) -> colorMap["tagged"] - highestValue < kondoExposed_lowValue -> "#FFFFFF" - highestValue < kondoExposed_mediumValue -> colorMap["lowValue"] - highestValue < kondoExposed_highValue -> colorMap["mediumValue"] - highestValue < kondoExposed_insaneValue -> colorMap["highValue"] + highestValue < lowValue -> "#FFFFFF" + highestValue < mediumValue -> colorMap["lowValue"] + highestValue < highValue -> colorMap["mediumValue"] + highestValue < insaneValue -> colorMap["highValue"] else -> colorMap["insaneValue"] } ?: "#FFFFFF" val colorInt = color.drop(1).toInt(16) @@ -183,7 +182,7 @@ open class plugin : Plugin() { val haValue = if (itemDef.id == coindId) item.value.amount else (itemDef.cost * 0.6 * item.value.amount).roundToInt() val geValue = (gePriceMap[itemDef.id.toString()]?.toInt() ?: 0) * item.value.amount val highestValue = maxOf(haValue, geValue) - return !((highestValue < kondoExposed_hideBelowValue || isHidden(itemDef.id)) && !isTagged(itemDef.id)) + return !((highestValue < hideBelowValue || isHidden(itemDef.id)) && !isTagged(itemDef.id)) } override fun OnMiniMenuCreate(currentEntries: Array?) { @@ -200,7 +199,7 @@ open class plugin : Plugin() { private fun ignoreItem(itemId: Int): Runnable { return Runnable { - val existingIgnores = kondoExposed_ignoredItems.toMutableList() + val existingIgnores = ignoredItems.toMutableList() if (existingIgnores.contains(itemId)) { existingIgnores.remove(itemId) @@ -215,7 +214,7 @@ open class plugin : Plugin() { private fun tagItem(itemId: Int): Runnable { return Runnable { - val existingTags = kondoExposed_taggedItems.toMutableList() + val existingTags = taggedItems.toMutableList() if (existingTags.contains(itemId)) { existingTags.remove(itemId) @@ -230,28 +229,28 @@ open class plugin : Plugin() { private fun resetConfig() { - kondoExposed_lowValue = 5000 - kondoExposed_mediumValue = 20000 - kondoExposed_highValue = 50000 - kondoExposed_insaneValue = 100000 - kondoExposed_hideBelowValue = 0 - kondoExposed_useLiveGEPrices = true + lowValue = 5000 + mediumValue = 20000 + highValue = 50000 + insaneValue = 100000 + hideBelowValue = 0 + useLiveGEPrices = true StoreData("ground-item-tags",""); StoreData("ground-item-ignore",""); - StoreData("low-value", kondoExposed_lowValue) - StoreData("ground-item-use-remote", kondoExposed_useLiveGEPrices) - StoreData("medium-value", kondoExposed_mediumValue) - StoreData("high-value", kondoExposed_highValue) - StoreData("insane-value", kondoExposed_insaneValue) - StoreData("hide-below-value", kondoExposed_hideBelowValue) + StoreData("low-value", lowValue) + StoreData("ground-item-use-remote", useLiveGEPrices) + StoreData("medium-value", mediumValue) + StoreData("high-value", highValue) + StoreData("insane-value", insaneValue) + StoreData("hide-below-value", hideBelowValue) } private fun displayRanges() { - val low = kondoExposed_lowValue - val medium = kondoExposed_mediumValue - val high = kondoExposed_highValue - val insane = kondoExposed_insaneValue - val hide = kondoExposed_hideBelowValue + val low = lowValue + val medium = mediumValue + val high = highValue + val insane = insaneValue + val hide = hideBelowValue SendMessage("== Ground Item Config ==") SendMessage("Low: $low") @@ -260,12 +259,12 @@ open class plugin : Plugin() { SendMessage("Insane: $insane") SendMessage("Hide Below: $hide") SendMessage("-- Ignored Items --") - for(item in kondoExposed_ignoredItems){ + for(item in ignoredItems){ val itemDef = ObjTypeList.get(item) SendMessage("Ignored: ${itemDef.name} ${itemDef.id}") } SendMessage("-- Tagged Items --") - for(item in kondoExposed_taggedItems){ + for(item in taggedItems){ val itemDef = ObjTypeList.get(item) SendMessage("Tagged: ${itemDef.name} ${itemDef.id}") } @@ -278,19 +277,19 @@ open class plugin : Plugin() { } fun OnKondoValueUpdated() { - StoreData("ground-item-tags",kondoExposed_taggedItems); - StoreData("ground-item-ignore",kondoExposed_ignoredItems); - StoreData("low-value", kondoExposed_lowValue) - StoreData("medium-value", kondoExposed_mediumValue) - StoreData("high-value", kondoExposed_highValue) - StoreData("insane-value", kondoExposed_insaneValue) - StoreData("ground-item-use-remote", kondoExposed_useLiveGEPrices) - StoreData("hide-below-value", kondoExposed_hideBelowValue) + StoreData("ground-item-tags",taggedItems); + StoreData("ground-item-ignore",ignoredItems); + StoreData("low-value", lowValue) + StoreData("medium-value", mediumValue) + StoreData("high-value", highValue) + StoreData("insane-value", insaneValue) + StoreData("ground-item-use-remote", useLiveGEPrices) + StoreData("hide-below-value", hideBelowValue) gePriceMap = loadGEPrices(); } fun loadGEPrices(): Map { - return if (kondoExposed_useLiveGEPrices) { + return if (useLiveGEPrices) { try { println("GroundItems: Loading Remote GE Prices") val url = URL("https://cdn.2009scape.org/gedata/latest.json") @@ -325,7 +324,7 @@ open class plugin : Plugin() { } else { try { println("GroundItems: Loading Local GE Prices") - BufferedReader(InputStreamReader(GroundItems.plugin::class.java.getResourceAsStream("item_configs.json"), StandardCharsets.UTF_8)) + BufferedReader(InputStreamReader(plugin::class.java.getResourceAsStream("res/item_configs.json"), StandardCharsets.UTF_8)) .useLines { lines -> val json = lines.joinToString("\n") val items = json.trim().removeSurrounding("[", "]").split("},").map { it.trim() + "}" } diff --git a/plugin-playground/src/main/kotlin/GroundItems/plugin.properties b/plugin-playground/src/main/kotlin/GroundItems/plugin.properties index e14f44c..c77a215 100644 --- a/plugin-playground/src/main/kotlin/GroundItems/plugin.properties +++ b/plugin-playground/src/main/kotlin/GroundItems/plugin.properties @@ -5,4 +5,4 @@ Commands:\ ::(tag,ignore)item ID\ ::(reset)groundconfig\ Special thanks to Chisato for the original skeleton. -VERSION=1.2 \ No newline at end of file +VERSION=1.3 \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/GroundItems/item_configs.json b/plugin-playground/src/main/kotlin/GroundItems/res/item_configs.json similarity index 100% rename from plugin-playground/src/main/kotlin/GroundItems/item_configs.json rename to plugin-playground/src/main/kotlin/GroundItems/res/item_configs.json From a31437ef82bc8d1d2e5ca5890391fcafb92dd31e Mon Sep 17 00:00:00 2001 From: downthecrop Date: Tue, 8 Oct 2024 01:28:12 -0700 Subject: [PATCH 05/47] Automatically add optional res folder into output --- plugin-playground/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugin-playground/build.gradle b/plugin-playground/build.gradle index c5f4a9f..a1644a7 100644 --- a/plugin-playground/build.gradle +++ b/plugin-playground/build.gradle @@ -110,4 +110,10 @@ task buildPlugins(type: Copy, dependsOn: classes) { from "build/classes/kotlin/main" into pluginsPath } + + // Find and copy any 'res' directories from 'src/main/kotlin/**/res/' + copy { + from fileTree(dir: "src/main/kotlin", include: "**/res/**") + into pluginsPath + } } \ No newline at end of file From 413601d0e505963f8dc33b7e21d93e285f3b2f46 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Tue, 8 Oct 2024 01:34:06 -0700 Subject: [PATCH 06/47] Make PluginInfo public --- client/src/main/java/plugin/PluginInfo.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/main/java/plugin/PluginInfo.java b/client/src/main/java/plugin/PluginInfo.java index 01fddc6..1550394 100644 --- a/client/src/main/java/plugin/PluginInfo.java +++ b/client/src/main/java/plugin/PluginInfo.java @@ -13,10 +13,10 @@ import java.util.Properties; * A data class for storing information about plugins. * @author ceikry */ -class PluginInfo { - double version; - String author; - String description; +public class PluginInfo { + public double version; + public String author; + public String description; public PluginInfo(String author, String description, double version) { this.version = version; From de5cbda4f9c0cc7c25eb0b8ac5724dc69b162c79 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 13 Oct 2024 00:04:42 -0700 Subject: [PATCH 07/47] Restore comments, remove the black spacer bar on platforms where it is not required --- .../src/main/kotlin/KondoKit/plugin.kt | 13 ++++++++----- .../src/main/kotlin/ToggleResizableSD/plugin.kt | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index e8233f9..1bd9ecd 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -66,7 +66,7 @@ class plugin : Plugin() { @Exposed(description = "Start minimized/collapsed by default") var launchMinimized = false - private const val FIXED_WIDTH = 782 + private const val FIXED_WIDTH = 765 private const val NAVBAR_WIDTH = 30 private const val MAIN_CONTENT_WIDTH = 242 private const val WRENCH_ICON = 907 @@ -118,16 +118,19 @@ class plugin : Plugin() { private fun UpdateDisplaySettings() { val mode = GetWindowMode() val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH + val osName = System.getProperty("os.name").toLowerCase() + val offset = if (osName == "win") 16 else 0 when (mode) { WindowMode.FIXED -> { - if (frame.width < FIXED_WIDTH + currentScrollPaneWidth) { - frame.setSize(FIXED_WIDTH + currentScrollPaneWidth, frame.height) + if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + offset) { + frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + offset, frame.height) } - val difference = frame.width - (FIXED_WIDTH + currentScrollPaneWidth) + + val difference = frame.width - (FIXED_WIDTH + offset + currentScrollPaneWidth) GameShell.leftMargin = difference / 2 } WindowMode.RESIZABLE -> { - GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + 16) + GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + offset) } } rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) diff --git a/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.kt b/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.kt index 2ce17cd..58ed363 100644 --- a/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.kt +++ b/plugin-playground/src/main/kotlin/ToggleResizableSD/plugin.kt @@ -57,6 +57,7 @@ class plugin : Plugin() { } fun toggleResizableSd() { + //We only want to toggle resizable SD when we are logged in and the lobby/welcome interface is not open. if (InterfaceList.aClass13_26 == null || client.gameState != 30) { return } @@ -85,6 +86,7 @@ class plugin : Plugin() { override fun OnLogout() { if (DisplayMode.resizableSD && wantHd) { + //Because resizable SD always uses the "HD" size canvas/window mode (check the in-game Graphics Options with resizeable SD enabled if you don't believe me!), useHD becomes true when logging out, so logging out with resizeSD enabled means "HD" will always be enabled on the login screen after logging out, so we might as well fix the HD flyover by setting resizableSD to false first, and then calling setWindowMode to replace the canvas and set newMode to 2. DisplayMode.resizableSD = false DisplayMode.setWindowMode(true, 2, GameShell.frameWidth, GameShell.frameHeight) } From b00960184882ef87f5a2a2747e074dd07e0bcffc Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 13 Oct 2024 00:25:07 -0700 Subject: [PATCH 08/47] contains instead of equals for os.name --- plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 1bd9ecd..8628cfa 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -119,7 +119,7 @@ class plugin : Plugin() { val mode = GetWindowMode() val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH val osName = System.getProperty("os.name").toLowerCase() - val offset = if (osName == "win") 16 else 0 + val offset = if (osName.contains("win")) 16 else 0 when (mode) { WindowMode.FIXED -> { if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + offset) { From 5e900044749c7b35e9337317ee8f2f25836bf4c4 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 14 Oct 2024 01:57:09 -0700 Subject: [PATCH 09/47] add support for custom offsets --- .../src/main/kotlin/KondoKit/plugin.kt | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 8628cfa..ea67995 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -57,15 +57,19 @@ class plugin : Plugin() { val primaryColor = Color(165, 165, 165) // Color for "XP Gained:" val secondaryColor = Color(255, 255, 255) // Color for "0" - @Exposed(description = "Default: true, Use Local JSON or the prices from the Live/Stable server API") + @Exposed("Default: true, Use Local JSON or the prices from the Live/Stable server API") var useLiveGEPrices = true - @Exposed(description = "Used to calculate Combat Actions until next level.") + @Exposed("Used to calculate Combat Actions until next level.") var playerXPMultiplier = 5 - @Exposed(description = "Start minimized/collapsed by default") + @Exposed("Start minimized/collapsed by default") var launchMinimized = false + @Exposed("Default 16 on Windows, 0 Linux/macOS. If Kondo is not " + + "perfectly snapped to the edge of the game due to window chrome you can update this to fix it") + var uiOffset = 0 + private const val FIXED_WIDTH = 765 private const val NAVBAR_WIDTH = 30 private const val MAIN_CONTENT_WIDTH = 242 @@ -84,6 +88,7 @@ class plugin : Plugin() { private var lastLogin = "" private var initialized = false; private var lastClickTime = 0L + private var lastUIOffset = 0 } fun allSpritesLoaded() : Boolean { @@ -118,19 +123,18 @@ class plugin : Plugin() { private fun UpdateDisplaySettings() { val mode = GetWindowMode() val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH - val osName = System.getProperty("os.name").toLowerCase() - val offset = if (osName.contains("win")) 16 else 0 + lastUIOffset = uiOffset when (mode) { WindowMode.FIXED -> { - if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + offset) { - frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + offset, frame.height) + if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + uiOffset) { + frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + uiOffset, frame.height) } - val difference = frame.width - (FIXED_WIDTH + offset + currentScrollPaneWidth) + val difference = frame.width - (FIXED_WIDTH + uiOffset + currentScrollPaneWidth) GameShell.leftMargin = difference / 2 } WindowMode.RESIZABLE -> { - GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + offset) + GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + uiOffset) } } rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) @@ -143,6 +147,11 @@ class plugin : Plugin() { StoreData("kondoPlayerXPMultiplier", playerXPMultiplier) LootTrackerView.gePriceMap = LootTrackerView.loadGEPrices() StoreData("kondoLaunchMinimized", launchMinimized) + StoreData("kondoUIOffset", uiOffset) + if(lastUIOffset != uiOffset){ + UpdateDisplaySettings() + reloadInterfaces = true + } } override fun OnMiniMenuCreate(currentEntries: Array?) { @@ -288,6 +297,8 @@ class plugin : Plugin() { // Restore saved values useLiveGEPrices = (GetData("kondoUseRemoteGE") as? Boolean) ?: true playerXPMultiplier = (GetData("kondoPlayerXPMultiplier") as? Int) ?: 5 + val osName = System.getProperty("os.name").toLowerCase() + uiOffset = (GetData("kondoUIOffset") as? Int) ?: if (osName.contains("win")) 16 else 0 launchMinimized = (GetData("kondoLaunchMinimized") as? Boolean) ?: false cardLayout = CardLayout() From f8dcbfafdb03ce6495be71ba7a59886822074791 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 14 Oct 2024 23:24:14 -0700 Subject: [PATCH 10/47] prevent text wrapping, prevent logintimer from reloading (preserve time) --- plugin-playground/src/main/kotlin/KondoKit/Helpers.kt | 6 ++++-- plugin-playground/src/main/kotlin/LoginTimer/plugin.kt | 4 ++++ .../src/main/kotlin/LoginTimer/plugin.properties | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt index 066edd1..faec99f 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt @@ -191,8 +191,10 @@ object Helpers { } fun formatHtmlLabelText(text1: String, color1: Color, text2: String, color2: Color): String { - return "$text1" + - "$text2" + return "
" + + "$text1" + + "$text2" + + "
" } fun formatNumber(value: Int): String { diff --git a/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt b/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt index 0ba67f7..806f726 100644 --- a/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt +++ b/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt @@ -35,6 +35,10 @@ class plugin : Plugin() { displayMessageCounter = 0 } + override fun OnPluginsReloaded(): Boolean { + return true + } + override fun Draw(timeDelta: Long) { if (component == null) return diff --git a/plugin-playground/src/main/kotlin/LoginTimer/plugin.properties b/plugin-playground/src/main/kotlin/LoginTimer/plugin.properties index 1ebf1f5..1f9beaa 100644 --- a/plugin-playground/src/main/kotlin/LoginTimer/plugin.properties +++ b/plugin-playground/src/main/kotlin/LoginTimer/plugin.properties @@ -1,3 +1,3 @@ AUTHOR='Woahscam, Ceikry' DESCRIPTION='Displays the session time played, system time, or no time over the "Report Abuse" button.' -VERSION=1.2 \ No newline at end of file +VERSION=1.1 \ No newline at end of file From 59100a036d0ce153c1218b2385414f7015c00afc Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 14 Oct 2024 23:35:01 -0700 Subject: [PATCH 11/47] logintimer reset on login but not during resize event ect --- plugin-playground/src/main/kotlin/LoginTimer/plugin.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt b/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt index 806f726..5cd6467 100644 --- a/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt +++ b/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt @@ -39,6 +39,10 @@ class plugin : Plugin() { return true } + override fun OnLogin() { + initTime = System.currentTimeMillis() + } + override fun Draw(timeDelta: Long) { if (component == null) return @@ -138,6 +142,9 @@ class plugin : Plugin() { API.InsertMiniMenuEntry("Disable Timer", "") { timeMode = DEFAULT_TIME_MODE } + API.InsertMiniMenuEntry("Reset Play Time", "") { + initTime = System.currentTimeMillis() + } } } } \ No newline at end of file From 0ab6ed38681933a19e392a683566f812a650ce99 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Fri, 18 Oct 2024 19:41:45 -0700 Subject: [PATCH 12/47] track login state withint logintimer plugin --- plugin-playground/src/main/kotlin/LoginTimer/plugin.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt b/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt index 5cd6467..1b8f60b 100644 --- a/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt +++ b/plugin-playground/src/main/kotlin/LoginTimer/plugin.kt @@ -25,6 +25,7 @@ class plugin : Plugin() { private var timeMode = TIME_MODE_INITIALIZATION private var initTime: Long = 0 + private var logoutFlag = true private var displayMessageCounter = 0 private var component: Component? = null @@ -40,7 +41,13 @@ class plugin : Plugin() { } override fun OnLogin() { - initTime = System.currentTimeMillis() + if(logoutFlag) + initTime = System.currentTimeMillis() + logoutFlag = false + } + + override fun OnLogout() { + logoutFlag = true } override fun Draw(timeDelta: Long) { From 1eee2a531bca1fffbe7435db492fef694e20237c Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 20 Oct 2024 22:21:52 -0700 Subject: [PATCH 13/47] Move AA Disable before GLInit --- plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index ea67995..368cc00 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -43,6 +43,7 @@ import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import javax.swing.* + @Target(AnnotationTarget.FIELD) @Retention(AnnotationRetention.RUNTIME) annotation class Exposed(val description: String = "") @@ -120,6 +121,13 @@ class plugin : Plugin() { lastLogin = Player.usernameInput.toString() } + override fun Init() { + // Disable Font AA + System.setProperty("sun.java2d.opengl", "false"); + System.setProperty("awt.useSystemAAFontSettings", "off"); + System.setProperty("swing.aatext", "false"); + } + private fun UpdateDisplaySettings() { val mode = GetWindowMode() val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH @@ -263,10 +271,6 @@ class plugin : Plugin() { val frame: Frame? = GameShell.frame if (frame != null) { - // Disable Font AA - System.setProperty("awt.useSystemAAFontSettings", "off") - System.setProperty("swing.aatext", "false") - loadFont() try { From d779f65db4967ced3a320ad300ceb032e03e6af7 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 21 Oct 2024 20:16:25 -0700 Subject: [PATCH 14/47] Display other loaded plugins in the config --- .../kotlin/KondoKit/ReflectiveEditorView.kt | 59 +++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt index 40bad3d..270c41b 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt @@ -27,6 +27,7 @@ import kotlin.math.ceil object ReflectiveEditorView { var reflectiveEditorView: JPanel? = null + val loadedPlugins: MutableList = mutableListOf() fun createReflectiveEditorView() { val reflectiveEditorPanel = JPanel(BorderLayout()) reflectiveEditorPanel.background = VIEW_BACKGROUND_COLOR @@ -38,6 +39,7 @@ object ReflectiveEditorView { fun addPlugins(reflectiveEditorView: JPanel) { reflectiveEditorView.removeAll() // clear previous + loadedPlugins.clear() try { val loadedPluginsField = PluginRepository::class.java.getDeclaredField("loadedPlugins") loadedPluginsField.isAccessible = true @@ -49,8 +51,57 @@ object ReflectiveEditorView { } catch (e: Exception) { e.printStackTrace() } + + // Add a centered box for plugins that have no exposed fields + if (loadedPlugins.isNotEmpty()) { + val noExposedPanel = JPanel(BorderLayout()) + noExposedPanel.background = VIEW_BACKGROUND_COLOR + noExposedPanel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10) + + val label = JLabel("Loaded Plugins without Exposed Fields", SwingConstants.CENTER) + label.font = Font("RuneScape Small", Font.PLAIN, 16) + label.foreground = primaryColor + noExposedPanel.add(label, BorderLayout.NORTH) + + val pluginsList = JList(loadedPlugins.toTypedArray()) + pluginsList.background = WIDGET_COLOR + pluginsList.foreground = secondaryColor + pluginsList.font = Font("RuneScape Small", Font.PLAIN, 16) + + // Wrap the JList in a JScrollPane with a fixed height + val maxScrollPaneHeight = 200 + val scrollPane = JScrollPane(pluginsList).apply { + verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED + horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER + } + + // Create a wrapper panel with BoxLayout to constrain the scroll pane + val scrollPaneWrapper = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + add(scrollPane) + } + + noExposedPanel.add(scrollPaneWrapper, BorderLayout.CENTER) + + // Center the panel within the reflectiveEditorView + val centeredPanel = JPanel().apply { + preferredSize = Dimension(240, maxScrollPaneHeight) + maximumSize = preferredSize + minimumSize = preferredSize + } + centeredPanel.layout = BoxLayout(centeredPanel, BoxLayout.Y_AXIS) + centeredPanel.add(Box.createVerticalGlue()) + centeredPanel.add(noExposedPanel) + centeredPanel.add(Box.createVerticalGlue()) + + reflectiveEditorView.add(Box.createVerticalStrut(10)) + reflectiveEditorView.add(centeredPanel) + } + + reflectiveEditorView.revalidate() - reflectiveEditorView.repaint() + if(plugin.StateManager.focusedView == "REFLECTIVE_EDITOR_VIEW") + reflectiveEditorView.repaint() } private fun addPluginToEditor(reflectiveEditorView: JPanel, pluginInfo : PluginInfo, plugin: Plugin) { @@ -210,9 +261,9 @@ object ReflectiveEditorView { reflectiveEditorView.add(Box.createVerticalStrut(5)) } } - reflectiveEditorView.revalidate() - if(KondoKit.plugin.StateManager.focusedView == "REFLECTIVE_EDITOR_VIEW") - reflectiveEditorView.repaint() + else { + loadedPlugins.add(plugin.javaClass.`package`.name); + } } var customToolTipWindow: JWindow? = null From f09de70a303c7c9f32bfb4c1e24133b61fc5ccd6 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 21 Oct 2024 21:09:22 -0700 Subject: [PATCH 15/47] Draw sync reset actions --- .../main/kotlin/KondoKit/LootTrackerView.kt | 61 ++++++++++--------- .../src/main/kotlin/KondoKit/XPTrackerView.kt | 9 +-- .../src/main/kotlin/KondoKit/plugin.kt | 18 ++++++ 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt index 459b84f..e293408 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt @@ -538,39 +538,44 @@ object LootTrackerView { } popupMenu.add(menuItem1) menuItem1.addActionListener { - lootTrackerView?.removeAll() - npcKillCounts.clear() - lootItemPanels.clear() - totalTrackerWidget = createTotalLootWidget() - - val wrapped = wrappedWidget(totalTrackerWidget!!.container) - val _popupMenu = resetLootTrackerMenu() - - // Create a custom MouseListener - val rightClickListener = object : MouseAdapter() { - override fun mousePressed(e: MouseEvent) { - if (e.isPopupTrigger) { - _popupMenu.show(e.component, e.x, e.y) - } - } - - override fun mouseReleased(e: MouseEvent) { - if (e.isPopupTrigger) { - _popupMenu.show(e.component, e.x, e.y) - } - } + plugin.registerDrawAction { + resetLootTracker() } - addMouseListenerToAll(wrapped,rightClickListener) - wrapped.addMouseListener(rightClickListener) - lootTrackerView?.add(Box.createVerticalStrut(5)) - lootTrackerView?.add(wrapped) - lootTrackerView?.add(Box.createVerticalStrut(10)) - lootTrackerView?.revalidate() - lootTrackerView?.repaint() } return popupMenu } + private fun resetLootTracker(){ + lootTrackerView?.removeAll() + npcKillCounts.clear() + lootItemPanels.clear() + totalTrackerWidget = createTotalLootWidget() + + val wrapped = wrappedWidget(totalTrackerWidget!!.container) + val _popupMenu = resetLootTrackerMenu() + + // Create a custom MouseListener + val rightClickListener = object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + if (e.isPopupTrigger) { + _popupMenu.show(e.component, e.x, e.y) + } + } + + override fun mouseReleased(e: MouseEvent) { + if (e.isPopupTrigger) { + _popupMenu.show(e.component, e.x, e.y) + } + } + } + addMouseListenerToAll(wrapped,rightClickListener) + wrapped.addMouseListener(rightClickListener) + lootTrackerView?.add(Box.createVerticalStrut(5)) + lootTrackerView?.add(wrapped) + lootTrackerView?.add(Box.createVerticalStrut(10)) + lootTrackerView?.revalidate() + lootTrackerView?.repaint() + } class FixedSizePanel(private val fixedSize: Dimension) : JPanel() { override fun getPreferredSize(): Dimension { diff --git a/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt index ff41e11..a30030c 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt @@ -1,10 +1,10 @@ package KondoKit +import KondoKit.Helpers.addMouseListenerToAll import KondoKit.Helpers.formatHtmlLabelText import KondoKit.Helpers.formatNumber import KondoKit.Helpers.getProgressBarColor import KondoKit.Helpers.getSpriteId -import KondoKit.Helpers.addMouseListenerToAll import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.plugin.Companion.IMAGE_SIZE import KondoKit.plugin.Companion.LVL_ICON @@ -295,14 +295,9 @@ object XPTrackerView { // Add menu items to the popup menu popupMenu.add(menuItem1) - //popupMenu.add(menuItem2) - //popupMenu.add(menuItem3) // Add action listeners to each menu item (optional) - menuItem1.addActionListener { resetXPTracker(xpTrackerView!!) } - //menuItem2.addActionListener { println("Option 2 selected") } - //menuItem3.addActionListener { println("Option 3 selected") } - + menuItem1.addActionListener { plugin.registerDrawAction { resetXPTracker(xpTrackerView!!) } } return popupMenu } diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 368cc00..046c0fe 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -90,6 +90,13 @@ class plugin : Plugin() { private var initialized = false; private var lastClickTime = 0L private var lastUIOffset = 0 + private val drawActions = mutableListOf<() -> Unit>() + + fun registerDrawAction(action: () -> Unit) { + synchronized(drawActions) { + drawActions.add(action) + } + } } fun allSpritesLoaded() : Boolean { @@ -259,6 +266,17 @@ class plugin : Plugin() { accumulatedTime = 0L } + // Draw synced actions (that require to be done between glBegin and glEnd) + if (drawActions.isNotEmpty()) { + synchronized(drawActions) { + val actionsCopy = drawActions.toList() + drawActions.clear() + for (action in actionsCopy) { + action() + } + } + } + // Init in the draw call so we know we are between glBegin and glEnd for HD if(!initialized && mainLoadState >= loginScreen) { initKondoUI() From 72bf9a829735267c72624c7864b53cafbce809ae Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 21 Oct 2024 21:26:54 -0700 Subject: [PATCH 16/47] Drawsync loot items --- plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt index e293408..1702b04 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt @@ -412,7 +412,7 @@ object LootTrackerView { newDrops.forEach { drop -> val geValue = (gePriceMap[drop.id.toString()]?.toInt() ?: 0) * drop.quantity updateValueLabel(lootTrackerView, geValue.toString(), npcName) - addItemToLootPanel(lootTrackerView, drop, npcName) + plugin.registerDrawAction { addItemToLootPanel(lootTrackerView, drop, npcName) } updateTotalValue(geValue) } } From 2a059d1c029498324f627463954acf8c852ba6e7 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Tue, 22 Oct 2024 18:39:30 -0700 Subject: [PATCH 17/47] centralize all colors, begin themeing support --- .../src/main/kotlin/KondoKit/Helpers.kt | 4 + .../src/main/kotlin/KondoKit/HiscoresView.kt | 34 +-- .../main/kotlin/KondoKit/LootTrackerView.kt | 83 ++++--- .../src/main/kotlin/KondoKit/ProgressBar.kt | 10 +- .../kotlin/KondoKit/ReflectiveEditorView.kt | 19 +- .../main/kotlin/KondoKit/ScrollablePanel.kt | 4 +- .../kotlin/KondoKit/SpriteToBufferedImage.kt | 221 +++++++++++------- .../src/main/kotlin/KondoKit/XPTrackerView.kt | 48 ++-- .../src/main/kotlin/KondoKit/plugin.kt | 168 +++++++++++-- 9 files changed, 405 insertions(+), 186 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt index faec99f..bfcac22 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt @@ -190,6 +190,10 @@ object Helpers { } } + fun showAlert(message: String, title: String, type: Int){ + JOptionPane.showMessageDialog(null, message, title, type) + } + fun formatHtmlLabelText(text1: String, color1: Color, text2: String, color2: Color): String { return "
" + "$text1" + diff --git a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt index 3ceb86d..ecdeed0 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt @@ -7,10 +7,15 @@ import KondoKit.Helpers.formatHtmlLabelText import KondoKit.Helpers.getSpriteId import KondoKit.Helpers.showToast import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite +import KondoKit.plugin.Companion.POPUP_BACKGROUND +import KondoKit.plugin.Companion.POPUP_FOREGROUND +import KondoKit.plugin.Companion.TITLE_BAR_COLOR +import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor +import KondoKit.plugin.StateManager.focusedView import com.google.gson.Gson import plugin.api.API import rt4.Sprites @@ -27,6 +32,7 @@ import java.net.SocketTimeoutException import java.net.URL import javax.swing.* import javax.swing.border.MatteBorder +import kotlin.math.floor object Constants { // Sprite IDs @@ -38,7 +44,6 @@ object Constants { // Dimensions val SEARCH_FIELD_DIMENSION = Dimension(230, 30) val ICON_DIMENSION_SMALL = Dimension(12, 12) - val ICON_DIMENSION_MEDIUM = Dimension(18, 20) val ICON_DIMENSION_LARGE = Dimension(30, 30) val HISCORE_PANEL_DIMENSION = Dimension(230, 500) val FILTER_PANEL_DIMENSION = Dimension(230, 30) @@ -50,11 +55,9 @@ object Constants { val NUMBER_LABEL_DIMENSION = Dimension(20, 20) // Colors - val COLOR_BACKGROUND_DARK = Color(27, 27, 27) + val COLOR_BACKGROUND_DARK = WIDGET_COLOR val COLOR_BACKGROUND_MEDIUM = VIEW_BACKGROUND_COLOR - val COLOR_FOREGROUND_LIGHT = Color(200, 200, 200) - val COLOR_RED = Color.RED - val COLOR_SKILL_PANEL = Color(60, 60, 60) + val COLOR_FOREGROUND_LIGHT = POPUP_FOREGROUND // Fonts val FONT_ARIAL_PLAIN_14 = Font("Arial", Font.PLAIN, 14) @@ -67,6 +70,7 @@ var text: String = "" object HiscoresView { + const val VIEW_NAME = "HISCORE_SEARCH_VIEW" var hiScoreView: JPanel? = null class CustomSearchField(private val hiscoresPanel: JPanel) : Canvas() { @@ -137,9 +141,9 @@ object HiscoresView { } }) - Timer(1000) { + Timer(500) { cursorVisible = !cursorVisible - if(plugin.StateManager.focusedView == "HISCORE_SEARCH_VIEW") + if(focusedView == VIEW_NAME) repaint() }.start() } @@ -165,7 +169,7 @@ object HiscoresView { } if (text.isNotEmpty()) { - g.color = Constants.COLOR_RED + g.color = Color.RED g.drawString("x", width - 20, 20) } } @@ -305,13 +309,13 @@ object HiscoresView { summoning: Int, isMemberWorld: Boolean ): Double { - val base = (defence + hitpoints + Math.floor(prayer.toDouble() / 2)) * 0.25 + val base = (defence + hitpoints + floor(prayer.toDouble() / 2)) * 0.25 val melee = (attack + strength) * 0.325 - val range = Math.floor(ranged * 1.5) * 0.325 - val mage = Math.floor(magic * 1.5) * 0.325 + val range = floor(ranged * 1.5) * 0.325 + val mage = floor(magic * 1.5) * 0.325 val maxCombatType = maxOf(melee, range, mage) - val summoningFactor = if (isMemberWorld) Math.floor(summoning.toDouble() / 8) else 0.0 + val summoningFactor = if (isMemberWorld) floor(summoning.toDouble() / 8) else 0.0 return Math.round((base + maxCombatType + summoningFactor) * 1000.0) / 1000.0 } @@ -338,7 +342,7 @@ object HiscoresView { fun createHiscoreSearchView() { val hiscorePanel = JPanel().apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) - name = "HISCORE_SEARCH_VIEW" + name = VIEW_NAME background = Constants.COLOR_BACKGROUND_MEDIUM preferredSize = Constants.HISCORE_PANEL_DIMENSION maximumSize = preferredSize @@ -369,7 +373,7 @@ object HiscoresView { val playerNamePanel = JPanel().apply { layout = GridBagLayout() // This will center the JLabel both vertically and horizontally - background = WIDGET_COLOR + background = TOOLTIP_BACKGROUND.darker() preferredSize = Constants.FILTER_PANEL_DIMENSION maximumSize = preferredSize minimumSize = preferredSize @@ -436,6 +440,7 @@ object HiscoresView { val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.LVL_BAR_SPRITE)); val totalLevelIcon = ImageCanvas(bufferedImageSprite).apply { + fillColor = COLOR_BACKGROUND_DARK preferredSize = Constants.ICON_DIMENSION_LARGE size = Constants.ICON_DIMENSION_LARGE } @@ -457,6 +462,7 @@ object HiscoresView { val bufferedImageSprite2 = getBufferedImageFromSprite(API.GetSprite(Constants.COMBAT_LVL_SPRITE)) val combatLevelIcon = ImageCanvas(bufferedImageSprite2).apply { + fillColor = COLOR_BACKGROUND_DARK preferredSize = Constants.ICON_DIMENSION_LARGE size = Constants.ICON_DIMENSION_LARGE } diff --git a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt index 1702b04..3a0fc14 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt @@ -4,11 +4,17 @@ import KondoKit.Helpers.addMouseListenerToAll import KondoKit.Helpers.formatHtmlLabelText import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.XPTrackerView.wrappedWidget +import KondoKit.plugin.Companion.IMAGE_SIZE +import KondoKit.plugin.Companion.POPUP_BACKGROUND +import KondoKit.plugin.Companion.POPUP_FOREGROUND +import KondoKit.plugin.Companion.TITLE_BAR_COLOR +import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.TOTAL_XP_WIDGET_SIZE import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor +import KondoKit.plugin.StateManager.focusedView import plugin.api.API import rt4.* import java.awt.* @@ -30,6 +36,7 @@ object LootTrackerView { const val BAG_ICON = 900; val npcDeathSnapshots = mutableMapOf() var gePriceMap = loadGEPrices() + const val VIEW_NAME = "LOOT_TRACKER_VIEW"; private val lootItemPanels = mutableMapOf>() private val npcKillCounts = mutableMapOf() private var totalTrackerWidget: XPWidget? = null @@ -125,9 +132,10 @@ object LootTrackerView { addMouseListenerToAll(wrapped,rightClickListener) wrapped.addMouseListener(rightClickListener) add(wrapped) - add(Box.createVerticalStrut(10)) + add(Box.createVerticalStrut(8)) revalidate() - repaint() + if(focusedView == VIEW_NAME) + repaint() } } @@ -158,7 +166,7 @@ object LootTrackerView { xpLeftLabel = JLabel(), actionsRemainingLabel = JLabel(), xpPerHourLabel = l1, - progressBar = ProgressBar(0.0, Color(150, 50, 50)), + progressBar = ProgressBar(0.0, Color(0,0,0)), // unused. totalXpGained = 0, startTime = System.currentTimeMillis(), previousXp = 0 @@ -167,16 +175,19 @@ object LootTrackerView { private fun createWidgetPanel(bufferedImageSprite: BufferedImage, l1 : JLabel, l2 : JLabel): Panel { val imageCanvas = ImageCanvas(bufferedImageSprite).apply { - size = Dimension(width, height) + preferredSize = Dimension(bufferedImageSprite.width, bufferedImageSprite.height) + minimumSize = preferredSize + maximumSize = preferredSize + size = preferredSize background = WIDGET_COLOR } - val imageContainer = Panel(FlowLayout()).apply { + val imageContainer = Panel(BorderLayout()).apply { background = WIDGET_COLOR - add(imageCanvas) + add(imageCanvas, BorderLayout.NORTH) } - return Panel(BorderLayout(5, 5)).apply { + return Panel(BorderLayout(5, 0)).apply { background = WIDGET_COLOR preferredSize = TOTAL_XP_WIDGET_SIZE add(imageContainer, BorderLayout.WEST) @@ -185,7 +196,7 @@ object LootTrackerView { } private fun createTextPanel(l1 : JLabel, l2: JLabel): Panel { - return Panel(GridLayout(2, 1, 5, 5)).apply { + return Panel(GridLayout(2, 1, 5, 0)).apply { background = WIDGET_COLOR add(l1) add(l2) @@ -219,9 +230,10 @@ object LootTrackerView { lootPanel.parent.maximumSize = size lootPanel.parent.revalidate() lootPanel.parent.repaint() - lootPanel.revalidate() - lootPanel.repaint() + + if(focusedView == VIEW_NAME) + lootPanel.repaint() } } @@ -231,7 +243,7 @@ object LootTrackerView { } private fun createItemPanel(itemId: Int, quantity: Int): JPanel { - val bufferedImageSprite = getBufferedImageFromSprite(API.GetObjSprite(itemId, quantity, true, 0, 0)) + val bufferedImageSprite = getBufferedImageFromSprite(API.GetObjSprite(itemId, quantity, true, 1, 3153952)) // Create the panel for the item val itemPanel = FixedSizePanel(Dimension(36, 32)).apply { @@ -276,22 +288,22 @@ object LootTrackerView { val gePricePerItem = gePriceMap[itemDef.id.toString()]?.toInt() ?: 0 val totalGePrice = gePricePerItem * quantity val totalHaPrice = itemDef.cost * quantity - val geText = if (quantity > 1) " (${gePricePerItem} ea)" else "" - val haText = if (quantity > 1) " (${itemDef.cost} ea)" else "" - - val text = "
" + + val geText = if (quantity > 1) " (${formatValue(gePricePerItem)} ea)" else "" + val haText = if (quantity > 1) " (${formatValue(itemDef.cost)} ea)" else "" + val bgColor = Helpers.colorToHex(TOOLTIP_BACKGROUND) + val textColor = Helpers.colorToHex(secondaryColor) + val text = "
" + "${itemDef.name} x $quantity
" + - "GE: $totalGePrice ${geText}
" + - "HA: $totalHaPrice ${haText}
" + "GE: ${formatValue(totalGePrice)} ${geText}
" + + "HA: ${formatValue(totalHaPrice)} ${haText}
" val _font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) - val c = Color(50,50,50) if (customToolTipWindow == null) { customToolTipWindow = JWindow().apply { contentPane = JLabel(text).apply { border = BorderFactory.createLineBorder(Color.BLACK) isOpaque = true - background = c + background = TOOLTIP_BACKGROUND foreground = Color.WHITE font = _font } @@ -316,7 +328,8 @@ object LootTrackerView { panel.removeAll() panel.add(createItemPanel(itemId, quantity).components[0], BorderLayout.CENTER) panel.revalidate() - panel.repaint() + if(focusedView == VIEW_NAME) + panel.repaint() } private fun updateKillCountLabel(lootTrackerPanel: JPanel, npcName: String) { @@ -340,7 +353,8 @@ object LootTrackerView { text = "${formatValue(newValue)} gp" putClientProperty("val", newValue) revalidate() - repaint() + if(focusedView == VIEW_NAME) + repaint() } } } @@ -401,9 +415,10 @@ object LootTrackerView { findLootItemsPanel(lootTrackerView, npcName)?.let { } ?: run { lootTrackerView.add(createLootFrame(npcName)) - lootTrackerView.add(Box.createVerticalStrut(10)) + lootTrackerView.add(Box.createVerticalStrut(8)) lootTrackerView.revalidate() - lootTrackerView.repaint() + if(focusedView == VIEW_NAME) + lootTrackerView.repaint() } npcKillCounts[npcName] = npcKillCounts.getOrDefault(npcName, 0) + 1 @@ -427,7 +442,7 @@ object LootTrackerView { } val labelPanel = JPanel(BorderLayout()).apply { - background = Color(21, 21, 21) + background = TITLE_BAR_COLOR border = BorderFactory.createEmptyBorder(5, 5, 5, 5) maximumSize = Dimension(230, 24) minimumSize = maximumSize @@ -436,14 +451,14 @@ object LootTrackerView { val killCount = npcKillCounts.getOrPut(npcName) { 0 } val countLabel = JLabel(formatHtmlLabelText(npcName, secondaryColor, " x $killCount", primaryColor)).apply { - foreground = Color(200, 200, 200) + foreground = secondaryColor font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) horizontalAlignment = JLabel.LEFT name = "killCountLabel_$npcName" } val valueLabel = JLabel("0 gp").apply { - foreground = Color(200, 200, 200) + foreground = secondaryColor font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) horizontalAlignment = JLabel.RIGHT name = "valueLabel_$npcName" @@ -491,13 +506,13 @@ object LootTrackerView { val popupMenu = JPopupMenu() val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) - popupMenu.background = Color(45, 45, 45) + popupMenu.background = POPUP_BACKGROUND // Create menu items with custom font and colors val menuItem1 = JMenuItem("Remove").apply { font = rFont // Set custom font - background = Color(45, 45, 45) // Dark background for item - foreground = Color(220, 220, 220) // Light text color for item + background = POPUP_BACKGROUND // Dark background for item + foreground = POPUP_FOREGROUND // Light text color for item } popupMenu.add(menuItem1) menuItem1.addActionListener { @@ -509,7 +524,7 @@ object LootTrackerView { if (toRemoveIndex >= 0 && toRemoveIndex < components.size - 1) { val nextComponent = components[toRemoveIndex + 1] if (nextComponent is Box.Filler) { - // Nasty way to remove the Box.createVerticalStrut(10) after + // Nasty way to remove the Box.createVerticalStrut(8) after // the lootpanel. parent.remove(nextComponent) } @@ -528,13 +543,13 @@ object LootTrackerView { val popupMenu = JPopupMenu() val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) - popupMenu.background = Color(45, 45, 45) + popupMenu.background = POPUP_BACKGROUND // Create menu items with custom font and colors val menuItem1 = JMenuItem("Reset Loot Tracker").apply { font = rFont // Set custom font - background = Color(45, 45, 45) // Dark background for item - foreground = Color(220, 220, 220) // Light text color for item + background = POPUP_BACKGROUND // Dark background for item + foreground = POPUP_FOREGROUND // Light text color for item } popupMenu.add(menuItem1) menuItem1.addActionListener { @@ -572,7 +587,7 @@ object LootTrackerView { wrapped.addMouseListener(rightClickListener) lootTrackerView?.add(Box.createVerticalStrut(5)) lootTrackerView?.add(wrapped) - lootTrackerView?.add(Box.createVerticalStrut(10)) + lootTrackerView?.add(Box.createVerticalStrut(8)) lootTrackerView?.revalidate() lootTrackerView?.repaint() } diff --git a/plugin-playground/src/main/kotlin/KondoKit/ProgressBar.kt b/plugin-playground/src/main/kotlin/KondoKit/ProgressBar.kt index f5df980..2c5546f 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ProgressBar.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ProgressBar.kt @@ -1,5 +1,7 @@ package KondoKit +import KondoKit.plugin.Companion.PROGRESS_BAR_FILL +import KondoKit.plugin.Companion.secondaryColor import java.awt.Canvas import java.awt.Color import java.awt.Dimension @@ -26,24 +28,24 @@ class ProgressBar( g.fillRect(0, 0, width, this.height) // Draw the unfilled part of the progress bar - g.color = Color(61, 56, 49) // from Runelite + g.color = PROGRESS_BAR_FILL g.fillRect(width, 0, this.width - width, this.height) // Variables for text position val textY = this.height / 2 + 6 // Draw the current level on the far left - drawTextWithShadow(g, "Lvl. $currentLevel", 5, textY, Color(255, 255, 255)) + drawTextWithShadow(g, "Lvl. $currentLevel", 5, textY, secondaryColor) // Draw the percentage in the middle val percentageText = String.format("%.2f%%", progress) val percentageWidth = g.fontMetrics.stringWidth(percentageText) - drawTextWithShadow(g, percentageText, (this.width - percentageWidth) / 2, textY, Color(255, 255, 255)) + drawTextWithShadow(g, percentageText, (this.width - percentageWidth) / 2, textY, secondaryColor) // Draw the next level on the far right val nextLevelText = "Lvl. $nextLevel" val nextLevelWidth = g.fontMetrics.stringWidth(nextLevelText) - drawTextWithShadow(g, nextLevelText, this.width - nextLevelWidth - 5, textY, Color(255, 255, 255)) + drawTextWithShadow(g, nextLevelText, this.width - nextLevelWidth - 5, textY, secondaryColor) } override fun getPreferredSize(): Dimension { diff --git a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt index 270c41b..cd167c9 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt @@ -2,10 +2,13 @@ package KondoKit import KondoKit.Helpers.convertValue import KondoKit.Helpers.showToast +import KondoKit.plugin.Companion.TITLE_BAR_COLOR +import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor +import KondoKit.plugin.StateManager.focusedView import plugin.Plugin import plugin.PluginInfo import plugin.PluginRepository @@ -28,6 +31,7 @@ import kotlin.math.ceil object ReflectiveEditorView { var reflectiveEditorView: JPanel? = null val loadedPlugins: MutableList = mutableListOf() + const val VIEW_NAME = "REFLECTIVE_EDITOR_VIEW" fun createReflectiveEditorView() { val reflectiveEditorPanel = JPanel(BorderLayout()) reflectiveEditorPanel.background = VIEW_BACKGROUND_COLOR @@ -100,7 +104,7 @@ object ReflectiveEditorView { reflectiveEditorView.revalidate() - if(plugin.StateManager.focusedView == "REFLECTIVE_EDITOR_VIEW") + if(focusedView == VIEW_NAME) reflectiveEditorView.repaint() } @@ -128,7 +132,7 @@ object ReflectiveEditorView { label.font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) labelPanel.add(label, BorderLayout.CENTER) label.isOpaque = true - label.background = Color(21, 21, 21) + label.background = TITLE_BAR_COLOR reflectiveEditorView.add(labelPanel) for (field in exposedFields) { @@ -270,7 +274,6 @@ object ReflectiveEditorView { fun showCustomToolTip(text: String, component: JComponent) { val _font = Font("RuneScape Small", Font.PLAIN, 16) - val backgroundColor = Color(50, 50, 50) val maxWidth = 150 val lineHeight = 16 @@ -290,10 +293,12 @@ object ReflectiveEditorView { if (customToolTipWindow == null) { customToolTipWindow = JWindow().apply { - contentPane = JLabel("
$text
").apply { + val bgColor = Helpers.colorToHex(TOOLTIP_BACKGROUND) + val textColor = Helpers.colorToHex(secondaryColor) + contentPane = JLabel("
$text
").apply { border = BorderFactory.createLineBorder(Color.BLACK) isOpaque = true - background = backgroundColor + background = TOOLTIP_BACKGROUND foreground = Color.WHITE font = _font maximumSize = Dimension(maxWidth, Int.MAX_VALUE) @@ -304,7 +309,9 @@ object ReflectiveEditorView { } else { // Update the tooltip text val label = customToolTipWindow!!.contentPane as JLabel - label.text = "
$text
" + val bgColor = Helpers.colorToHex(TOOLTIP_BACKGROUND) + val textColor = Helpers.colorToHex(secondaryColor) + label.text = "
$text
" label.preferredSize = Dimension(maxWidth, requiredHeight) customToolTipWindow!!.pack() } diff --git a/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt index 44467a7..46f2b5a 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt @@ -1,8 +1,8 @@ package KondoKit +import KondoKit.plugin.Companion.SCROLL_BAR_COLOR import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import rt4.GameShell.frame -import java.awt.Color import java.awt.Graphics import java.awt.Graphics2D import java.awt.Rectangle @@ -147,7 +147,7 @@ class ScrollablePanel(private val content: JPanel) : JPanel() { if (showScrollbar) { val g2 = g as Graphics2D val scrollbarX = 238 - g2.color = Color(64, 64, 64) + g2.color = SCROLL_BAR_COLOR g2.fillRect(scrollbarX, scrollbarY, 2, scrollbarHeight) } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt b/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt index e273c98..ef7b298 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt @@ -4,109 +4,172 @@ import rt4.GlIndexedSprite import rt4.GlSprite import rt4.SoftwareIndexedSprite import rt4.SoftwareSprite +import java.awt.Color import java.awt.image.BufferedImage +// Define interfaces for common sprite types +interface BaseSprite { + val width: Int + val height: Int +} + +interface IndexedSprite : BaseSprite { + val pixels: ByteArray + val palette: IntArray +} + +interface NonIndexedSprite : BaseSprite { + val pixels: IntArray? +} + +// Adapter functions for existing sprite types +fun adaptSoftwareSprite(sprite: SoftwareSprite): NonIndexedSprite { + return object : NonIndexedSprite { + override val width: Int = sprite.width + override val height: Int = sprite.height + override val pixels: IntArray? = sprite.pixels + } +} + +fun adaptSoftwareIndexedSprite(sprite: SoftwareIndexedSprite): IndexedSprite { + return object : IndexedSprite { + override val width: Int = sprite.width + override val height: Int = sprite.height + override val pixels: ByteArray = sprite.pixels + override val palette: IntArray = sprite.pallet + } +} + +fun adaptGlSprite(sprite: GlSprite): NonIndexedSprite { + return object : NonIndexedSprite { + override val width: Int = sprite.width + override val height: Int = sprite.height + override val pixels: IntArray? = sprite.pixels + } +} + +fun adaptGlIndexedSprite(sprite: GlIndexedSprite): IndexedSprite { + return object : IndexedSprite { + override val width: Int = sprite.width + override val height: Int = sprite.height + override val pixels: ByteArray = sprite.pixels + override val palette: IntArray = sprite.pallet + } +} + object SpriteToBufferedImage { /** - * Converts a SoftwareSprite back into a BufferedImage. + * Converts a BaseSprite into a BufferedImage. + * + * Handles both indexed and non-indexed sprites, with optional tinting and grayscale. * * @param sprite The sprite to be converted. + * @param tint An optional Color to tint the image. + * @param grayscale If true, converts the image to grayscale. * @return The BufferedImage created from the sprite. */ - fun convertToBufferedImage(sprite: SoftwareSprite): BufferedImage { + fun convertToBufferedImage(sprite: BaseSprite, tint: Color? = null, grayscale: Boolean = false): BufferedImage { val width = sprite.width val height = sprite.height - val pixels = sprite.pixels - - // Create a BufferedImage with ARGB color model val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) - // Manually set pixels and print the pixel data - for (y in 0 until height) { - for (x in 0 until width) { - val pixel = pixels[y * width + x] - image.setRGB(x, y, pixel) + when (sprite) { + is IndexedSprite -> { + val pixels = sprite.pixels + val palette = sprite.palette + + // Manually set pixels using the palette + for (y in 0 until height) { + for (x in 0 until width) { + val index = pixels[y * width + x].toInt() and 0xFF + var color = palette[index] + + // Apply grayscale or tint if provided + val finalColor = if (grayscale) { + applyGrayscale(Color(color, true)) + } else if (tint != null) { + applyTint(Color(color, true), tint) + } else { + Color(color, true) + } + + image.setRGB(x, y, finalColor.rgb) + } + } + } + is NonIndexedSprite -> { + val pixels = sprite.pixels ?: return image // Handle null case for GlSprite + + // Manually set pixels directly + for (y in 0 until height) { + for (x in 0 until width) { + var color = pixels[y * width + x] + + // Apply grayscale or tint if provided + val finalColor = if (grayscale) { + applyGrayscale(Color(color, true)) + } else if (tint != null) { + applyTint(Color(color, true), tint) + } else { + Color(color, true) + } + + image.setRGB(x, y, finalColor.rgb) + } + } } } + return image } - fun convertToBufferedImage(sprite: SoftwareIndexedSprite): BufferedImage { - val width = sprite.width - val height = sprite.height - val pixels = sprite.pixels // byte[] - val palette = sprite.pallet + /** + * Applies a tint to a given color using the tint's alpha value to control the intensity. + * + * @param original The original color. + * @param tint The tint color to be applied, with alpha controlling the intensity. + * @return The tinted color. + */ + fun applyTint(original: Color, tint: Color): Color { + val alpha = tint.alpha / 255.0 // Normalize alpha to range [0, 1] + val invAlpha = 1.0 - alpha - // Create a BufferedImage with ARGB color model - val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) + // Blend the tint with the original color based on the alpha + val r = (original.red * invAlpha + tint.red * alpha).toInt().coerceIn(0, 255) + val g = (original.green * invAlpha + tint.green * alpha).toInt().coerceIn(0, 255) + val b = (original.blue * invAlpha + tint.blue * alpha).toInt().coerceIn(0, 255) - // Manually set pixels using the palette - for (y in 0 until height) { - for (x in 0 until width) { - // Get the index from the sprite's pixel array - val index = pixels[y * width + x].toInt() and 0xFF - // Map the index to a color in the palette - val color = palette[index] - // Set the ARGB color in the BufferedImage - image.setRGB(x, y, color) - } - } - return image - } - - fun convertToBufferedImage(sprite: GlIndexedSprite): BufferedImage { - val width = sprite.width - val height = sprite.height - val pixels = sprite.pixels // byte[] - val palette = sprite.pallet - - // Create a BufferedImage with ARGB color model - val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) - - // Manually set pixels using the palette - for (y in 0 until height) { - for (x in 0 until width) { - // Get the index from the sprite's pixel array - val index = pixels[y * width + x].toInt() and 0xFF - // Map the index to a color in the palette - val color = palette[index] - // Set the ARGB color in the BufferedImage - image.setRGB(x, y, color) - } - } - return image + return Color(r, g, b, original.alpha) } - fun convertToBufferedImage(sprite: GlSprite): BufferedImage { - val width = sprite.width - val height = sprite.height - val pixels = sprite.pixels - - // Create a BufferedImage with ARGB color model - val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) - - if(pixels == null) { - return image - } - - // Manually set pixels and print the pixel data - for (y in 0 until height) { - for (x in 0 until width) { - val pixel = pixels[y * width + x] - image.setRGB(x, y, pixel) - } - } - return image + /** + * Converts a color to grayscale. + * + * @param original The original color. + * @return The grayscale version of the color. + */ + fun applyGrayscale(original: Color): Color { + // Calculate the grayscale value using the luminosity method + val grayValue = (0.3 * original.red + 0.59 * original.green + 0.11 * original.blue).toInt() + return Color(grayValue, grayValue, grayValue, original.alpha) } - fun getBufferedImageFromSprite(sprite: Any?) : BufferedImage { - return when(sprite){ - is GlSprite -> convertToBufferedImage(sprite) - is SoftwareSprite -> convertToBufferedImage(sprite) - is SoftwareIndexedSprite -> convertToBufferedImage(sprite) - is GlIndexedSprite -> convertToBufferedImage(sprite) - else -> BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB) + /** + * Converts an unknown sprite object into a BufferedImage if it matches a known sprite type. + * + * @param sprite The sprite object to be converted. + * @param tint An optional Color to tint the image. + * @param grayscale If true, converts the image to grayscale. + * @return The BufferedImage created from the sprite or a default image if unsupported. + */ + fun getBufferedImageFromSprite(sprite: Any?, tint: Color? = null, grayscale: Boolean = false): BufferedImage { + return when (sprite) { + is SoftwareSprite -> convertToBufferedImage(adaptSoftwareSprite(sprite), tint, grayscale) + is SoftwareIndexedSprite -> convertToBufferedImage(adaptSoftwareIndexedSprite(sprite), tint, grayscale) + is GlSprite -> convertToBufferedImage(adaptGlSprite(sprite), tint, grayscale) + is GlIndexedSprite -> convertToBufferedImage(adaptGlIndexedSprite(sprite), tint, grayscale) + else -> BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB) // Default empty image for unsupported types } } } \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt index a30030c..b975194 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/XPTrackerView.kt @@ -8,6 +8,8 @@ import KondoKit.Helpers.getSpriteId import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.plugin.Companion.IMAGE_SIZE import KondoKit.plugin.Companion.LVL_ICON +import KondoKit.plugin.Companion.POPUP_BACKGROUND +import KondoKit.plugin.Companion.POPUP_FOREGROUND import KondoKit.plugin.Companion.TOTAL_XP_WIDGET_SIZE import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR @@ -15,6 +17,7 @@ import KondoKit.plugin.Companion.WIDGET_SIZE import KondoKit.plugin.Companion.playerXPMultiplier import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor +import KondoKit.plugin.StateManager.focusedView import plugin.api.API import java.awt.* import java.awt.event.MouseAdapter @@ -30,6 +33,7 @@ object XPTrackerView { var totalXPWidget: XPWidget? = null val initialXP: MutableMap = HashMap() var xpTrackerView: JPanel? = null + const val VIEW_NAME = "XP_TRACKER_VIEW" val npcHitpointsMap: Map = try { @@ -96,10 +100,10 @@ object XPTrackerView { xpWidget.xpGainedLabel.text = formatHtmlLabelText("XP Gained: ", primaryColor, formattedXp, secondaryColor) // Update the progress bar with current level, progress, and next level - xpWidget.progressBar.updateProgress(progress, currentLevel, if (currentLevel < 99) currentLevel + 1 else 99, plugin.StateManager.focusedView == "XP_TRACKER_VIEW") + xpWidget.progressBar.updateProgress(progress, currentLevel, if (currentLevel < 99) currentLevel + 1 else 99, focusedView == VIEW_NAME) xpWidget.previousXp = xp - if (plugin.StateManager.focusedView == "XP_TRACKER_VIEW") + if (focusedView == VIEW_NAME) xpWidget.container.repaint() } @@ -109,7 +113,7 @@ object XPTrackerView { totalXPWidget.totalXpGained += xpGainedSinceLastUpdate val formattedXp = formatNumber(totalXPWidget.totalXpGained) totalXPWidget.xpGainedLabel.text = formatHtmlLabelText("Gained: ", primaryColor, formattedXp, secondaryColor) - if (plugin.StateManager.focusedView == "XP_TRACKER_VIEW") + if (focusedView == VIEW_NAME) totalXPWidget.container.repaint() } @@ -148,7 +152,7 @@ object XPTrackerView { xpWidgets.clear() xpTrackerView.revalidate() - if (plugin.StateManager.focusedView == "XP_TRACKER_VIEW") + if (focusedView == VIEW_NAME) xpTrackerView.repaint() } @@ -164,10 +168,10 @@ object XPTrackerView { val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(LVL_ICON)) val imageContainer = Panel(FlowLayout()).apply { - preferredSize = IMAGE_SIZE - maximumSize = IMAGE_SIZE - minimumSize = IMAGE_SIZE - size = IMAGE_SIZE + preferredSize = Dimension(bufferedImageSprite.width, bufferedImageSprite.height) + maximumSize = preferredSize + minimumSize = preferredSize + size = preferredSize } bufferedImageSprite.let { image -> @@ -182,7 +186,7 @@ object XPTrackerView { imageContainer.size = Dimension(bufferedImageSprite.width, bufferedImageSprite.height) imageContainer.revalidate() - if(plugin.StateManager.focusedView == "XP_TRACKER_VIEW") + if(focusedView == VIEW_NAME) imageContainer.repaint() } @@ -221,7 +225,7 @@ object XPTrackerView { this.font = font }, xpPerHourLabel = xpPerHourLabel, - progressBar = ProgressBar(0.0, Color(150, 50, 50)), + progressBar = ProgressBar(0.0, Color.BLACK), // Unused totalXpGained = 0, startTime = System.currentTimeMillis(), previousXp = 0, @@ -272,25 +276,13 @@ object XPTrackerView { val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) - popupMenu.background = Color(45, 45, 45) + popupMenu.background = POPUP_BACKGROUND // Create menu items with custom font and colors val menuItem1 = JMenuItem("Reset Tracker").apply { font = rFont // Set custom font - background = Color(45, 45, 45) // Dark background for item - foreground = Color(220, 220, 220) // Light text color for item - } - - val menuItem2 = JMenuItem("Option 2").apply { - font = rFont - background = Color(45, 45, 45) - foreground = Color(220, 220, 220) - } - - val menuItem3 = JMenuItem("Option 3").apply { - font = rFont - background = Color(45, 45, 45) - foreground = Color(220, 220, 220) + background = POPUP_BACKGROUND // Dark background for item + foreground = POPUP_FOREGROUND // Light text color for item } // Add menu items to the popup menu @@ -333,7 +325,7 @@ object XPTrackerView { imageContainer.size = Dimension(image.width, image.height) // Ensure container respects the image size imageContainer.revalidate() - if(plugin.StateManager.focusedView == "XP_TRACKER_VIEW") + if(focusedView == VIEW_NAME) imageContainer.repaint() } @@ -374,7 +366,7 @@ object XPTrackerView { val levelPanel = Panel().apply { layout = BorderLayout(5, 0) - background = Color(43, 43, 43) + background = WIDGET_COLOR } val progressBarPanel = ProgressBar(0.0, getProgressBarColor(skillId)).apply { @@ -393,7 +385,7 @@ object XPTrackerView { widgetPanel.add(levelPanel, BorderLayout.SOUTH) widgetPanel.revalidate() - if(plugin.StateManager.focusedView == "XP_TRACKER_VIEW") + if(focusedView == VIEW_NAME) widgetPanel.repaint() return XPWidget( diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 046c0fe..daf92c1 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -4,6 +4,8 @@ import KondoKit.Constants.COMBAT_LVL_SPRITE import KondoKit.Helpers.formatHtmlLabelText import KondoKit.Helpers.formatNumber import KondoKit.Helpers.getSpriteId +import KondoKit.Helpers.showAlert +import KondoKit.Helpers.showToast import KondoKit.HiscoresView.createHiscoreSearchView import KondoKit.HiscoresView.hiScoreView import KondoKit.LootTrackerView.BAG_ICON @@ -26,6 +28,7 @@ import KondoKit.XPTrackerView.wrappedWidget import KondoKit.XPTrackerView.xpTrackerView import KondoKit.XPTrackerView.xpWidgets import KondoKit.plugin.StateManager.focusedView +import com.sun.org.apache.xpath.internal.operations.Bool import plugin.Plugin import plugin.api.* import plugin.api.API.* @@ -52,11 +55,26 @@ class plugin : Plugin() { companion object { val WIDGET_SIZE = Dimension(220, 50) val TOTAL_XP_WIDGET_SIZE = Dimension(220, 30) - val IMAGE_SIZE = Dimension(20, 20) - val WIDGET_COLOR = Color(30, 30, 30) - val VIEW_BACKGROUND_COLOR = Color(40, 40, 40) - val primaryColor = Color(165, 165, 165) // Color for "XP Gained:" - val secondaryColor = Color(255, 255, 255) // Color for "0" + val IMAGE_SIZE = Dimension(25, 23) + + // Default Theme Colors + var WIDGET_COLOR = Color(30, 30, 30) + var TITLE_BAR_COLOR = Color(21, 21, 21) + var VIEW_BACKGROUND_COLOR = Color(40, 40, 40) + var primaryColor = Color(165, 165, 165) // Color for "XP Gained:" + var secondaryColor = Color(255, 255, 255) // Color for "0" + var POPUP_BACKGROUND = Color(45, 45, 45) + var POPUP_FOREGROUND = Color(220, 220, 220) + var TOOLTIP_BACKGROUND = Color(50,50,50) + var SCROLL_BAR_COLOR = Color(64, 64, 64) + var PROGRESS_BAR_FILL = Color(61, 56, 49) + var NAV_TINT: Color? = null + var NAV_GREYSCALE = false + + var appliedTheme = ThemeType.RUNELITE + + @Exposed("Theme colors for KondoKit, requires a relaunch to apply.") + var theme = ThemeType.RUNELITE @Exposed("Default: true, Use Local JSON or the prices from the Live/Stable server API") var useLiveGEPrices = true @@ -90,6 +108,7 @@ class plugin : Plugin() { private var initialized = false; private var lastClickTime = 0L private var lastUIOffset = 0 + private const val HIDDEN_VIEW = "HIDDEN"; private val drawActions = mutableListOf<() -> Unit>() fun registerDrawAction(action: () -> Unit) { @@ -159,6 +178,14 @@ class plugin : Plugin() { fun OnKondoValueUpdated(){ StoreData("kondoUseRemoteGE", useLiveGEPrices) + StoreData("kondoTheme", theme.toString()) + if(appliedTheme != theme) { + showAlert( + "KondoKit Theme changes require a relaunch.", + "KondoKit", + JOptionPane.INFORMATION_MESSAGE + ) + } StoreData("kondoPlayerXPMultiplier", playerXPMultiplier) LootTrackerView.gePriceMap = LootTrackerView.loadGEPrices() StoreData("kondoLaunchMinimized", launchMinimized) @@ -191,7 +218,7 @@ class plugin : Plugin() { private fun searchHiscore(username: String): Runnable { return Runnable { - setActiveView("HISCORE_SEARCH_VIEW") + setActiveView(HiscoresView.VIEW_NAME) val customSearchField = hiScoreView?.let { HiscoresView.CustomSearchField(it) } customSearchField?.searchPlayer(username) ?: run { @@ -237,7 +264,7 @@ class plugin : Plugin() { xpTrackerView?.add(Box.createVerticalStrut(5)) xpTrackerView?.revalidate() - if(focusedView == "XP_TRACKER_VIEW") + if(focusedView == XPTrackerView.VIEW_NAME) xpTrackerView?.repaint() updateWidget(xpWidget, xp) @@ -290,6 +317,10 @@ class plugin : Plugin() { if (frame != null) { loadFont() + val themeIndex = (GetData("kondoTheme") as? String) ?: "RUNELITE" + theme = ThemeType.valueOf(themeIndex) + applyTheme(getTheme(theme)) + appliedTheme = theme try { UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel") @@ -337,10 +368,10 @@ class plugin : Plugin() { createLootTrackerView() createReflectiveEditorView() - mainContentPanel.add(ScrollablePanel(xpTrackerView!!), "XP_TRACKER_VIEW") - mainContentPanel.add(ScrollablePanel(hiScoreView!!), "HISCORE_SEARCH_VIEW") - mainContentPanel.add(ScrollablePanel(lootTrackerView!!), "LOOT_TRACKER_VIEW") - mainContentPanel.add(ScrollablePanel(reflectiveEditorView!!), "REFLECTIVE_EDITOR_VIEW") + mainContentPanel.add(ScrollablePanel(xpTrackerView!!), XPTrackerView.VIEW_NAME) + mainContentPanel.add(ScrollablePanel(hiScoreView!!), HiscoresView.VIEW_NAME) + mainContentPanel.add(ScrollablePanel(lootTrackerView!!), LootTrackerView.VIEW_NAME) + mainContentPanel.add(ScrollablePanel(reflectiveEditorView!!), ReflectiveEditorView.VIEW_NAME) val navPanel = Panel().apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) @@ -348,10 +379,10 @@ class plugin : Plugin() { preferredSize = Dimension(NAVBAR_WIDTH, frame.height) } - navPanel.add(createNavButton(LVL_ICON, "XP_TRACKER_VIEW")) - navPanel.add(createNavButton(MAG_SPRITE, "HISCORE_SEARCH_VIEW")) - navPanel.add(createNavButton(LOOT_ICON, "LOOT_TRACKER_VIEW")) - navPanel.add(createNavButton(WRENCH_ICON, "REFLECTIVE_EDITOR_VIEW")) + navPanel.add(createNavButton(LVL_ICON, XPTrackerView.VIEW_NAME)) + navPanel.add(createNavButton(MAG_SPRITE, HiscoresView.VIEW_NAME)) + navPanel.add(createNavButton(LOOT_ICON, LootTrackerView.VIEW_NAME)) + navPanel.add(createNavButton(WRENCH_ICON, ReflectiveEditorView.VIEW_NAME)) var rightPanel = Panel(BorderLayout()).apply { add(mainContentPanel, BorderLayout.CENTER) @@ -370,9 +401,9 @@ class plugin : Plugin() { rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) } if(!launchMinimized){ - setActiveView("XP_TRACKER_VIEW") + setActiveView(XPTrackerView.VIEW_NAME) } else { - setActiveView("HIDDEN") + setActiveView(HIDDEN_VIEW) } initialized = true pluginsReloaded = true @@ -410,7 +441,7 @@ class plugin : Plugin() { private fun setActiveView(viewName: String) { // Handle the visibility of the main content panel - if (viewName == "HIDDEN") { + if (viewName == HIDDEN_VIEW) { mainContentPanel.isVisible = false } else { if (!mainContentPanel.isVisible) { @@ -434,7 +465,7 @@ class plugin : Plugin() { } private fun createNavButton(spriteId: Int, viewName: String): JPanel { - val bufferedImageSprite = getBufferedImageFromSprite(GetSprite(spriteId)) + val bufferedImageSprite = getBufferedImageFromSprite(GetSprite(spriteId), NAV_TINT, NAV_GREYSCALE) val buttonSize = Dimension(NAVBAR_WIDTH, 32) val imageSize = Dimension((bufferedImageSprite.width / 1.2f).toInt(), (bufferedImageSprite.height / 1.2f).toInt()) val cooldownDuration = 100L @@ -536,4 +567,103 @@ class plugin : Plugin() { object StateManager { var focusedView: String = "" } + + fun applyTheme(theme: Theme) { + WIDGET_COLOR = theme.widgetColor + TITLE_BAR_COLOR = theme.titleBarColor + VIEW_BACKGROUND_COLOR = theme.viewBackgroundColor + primaryColor = theme.primaryColor + secondaryColor = theme.secondaryColor + POPUP_BACKGROUND = theme.popupBackground + POPUP_FOREGROUND = theme.popupForeground + TOOLTIP_BACKGROUND = theme.tooltipBackground + SCROLL_BAR_COLOR = theme.scrollBarColor + PROGRESS_BAR_FILL = theme.progressBarFill + NAV_TINT = theme.navTint + NAV_GREYSCALE = theme.navGreyScale + } + + enum class ThemeType { + RUNELITE, + DARKER_RUNELITE, + SARADOMIN, + ORION, + } + + fun getTheme(themeType: ThemeType): Theme { + return when (themeType) { + ThemeType.RUNELITE -> Theme( + widgetColor = Color(30, 30, 30), + titleBarColor = Color(21, 21, 21), + viewBackgroundColor = Color(40, 40, 40), + primaryColor = Color(165, 165, 165), + secondaryColor = Color(255, 255, 255), + popupBackground = Color(45, 45, 45), + popupForeground = Color(220, 220, 220), + tooltipBackground = Color(50, 50, 50), + scrollBarColor = Color(64, 64, 64), + progressBarFill = Color(61, 56, 49), + navTint = null, + navGreyScale = false + ) + ThemeType.DARKER_RUNELITE -> Theme( + widgetColor = Color(15, 15, 15), // Darker widget backgrounds + titleBarColor = Color(10, 10, 10), // Even darker title bar + viewBackgroundColor = Color(20, 20, 20), // Very dark background for the view + primaryColor = Color(140, 140, 140), // Darker shade for primary text + secondaryColor = Color(210, 210, 210), // Slightly muted white for secondary text + popupBackground = Color(25, 25, 25), // Very dark popup backgrounds + popupForeground = Color(200, 200, 200), // Slightly muted light gray for popup text + tooltipBackground = Color(30, 30, 30), // Darker tooltips background + scrollBarColor = Color(40, 40, 40), // Darker scroll bar + progressBarFill = Color(45, 40, 35), // Darker progress bar fill + navTint = null, //Color(20, 20, 20, 60), // No specific tint applied + navGreyScale = false // Navigation retains color (if applicable) + ) + ThemeType.ORION -> Theme( + widgetColor = Color(50, 50, 50), // Darker gray for widget backgrounds + titleBarColor = Color(35, 35, 35), // Very dark gray for the title bar + viewBackgroundColor = Color(60, 60, 60), // Medium-dark gray for view background + primaryColor = Color(180, 180, 180), // Lighter gray for primary text or highlights + secondaryColor = Color(210, 210, 210), // Light gray for secondary text + popupBackground = Color(45, 45, 45), // Dark gray for popup backgrounds + popupForeground = Color(230, 230, 230), // Light gray for popup text + tooltipBackground = Color(55, 55, 55), // Slightly darker gray for tooltips + scrollBarColor = Color(75, 75, 75), // Dark gray for scroll bars + progressBarFill = Color(100, 100, 100), // Medium gray for progress bar fill + navTint = null, + navGreyScale = true + ) + ThemeType.SARADOMIN -> Theme( + widgetColor = Color(75, 60, 45), + titleBarColor = Color(60, 48, 36), + viewBackgroundColor = Color(95, 76, 58), + primaryColor = Color(180, 150, 120), + secondaryColor = Color(230, 210, 190), + popupBackground = Color(70, 56, 42), + popupForeground = Color(220, 200, 180), + tooltipBackground = Color(80, 65, 50), + scrollBarColor = Color(100, 85, 70), + progressBarFill = Color(130, 110, 90), + navTint = null, + navGreyScale = false + ) + } + } + + + data class Theme( + val widgetColor: Color, + val titleBarColor: Color, + val viewBackgroundColor: Color, + val primaryColor: Color, + val secondaryColor: Color, + val popupBackground: Color, + val popupForeground: Color, + val tooltipBackground: Color, + val scrollBarColor: Color, + val progressBarFill: Color, + val navTint: Color?, + val navGreyScale: Boolean + ) } From 5948810ca7e45bee4ff963e8ae69caff5e3ff918 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Tue, 22 Oct 2024 21:26:54 -0700 Subject: [PATCH 18/47] Move themes to a new file, add color boost --- .../kotlin/KondoKit/SpriteToBufferedImage.kt | 76 ++++++++---- .../src/main/kotlin/KondoKit/Themes.kt | 94 +++++++++++++++ .../src/main/kotlin/KondoKit/plugin.kt | 113 +++--------------- 3 files changed, 160 insertions(+), 123 deletions(-) create mode 100644 plugin-playground/src/main/kotlin/KondoKit/Themes.kt diff --git a/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt b/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt index ef7b298..f955f95 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt @@ -66,9 +66,15 @@ object SpriteToBufferedImage { * @param sprite The sprite to be converted. * @param tint An optional Color to tint the image. * @param grayscale If true, converts the image to grayscale. + * @param brightnessBoost A multiplier to boost the brightness of the image. * @return The BufferedImage created from the sprite. */ - fun convertToBufferedImage(sprite: BaseSprite, tint: Color? = null, grayscale: Boolean = false): BufferedImage { + fun convertToBufferedImage( + sprite: BaseSprite, + tint: Color? = null, + grayscale: Boolean = false, + brightnessBoost: Float = 1.0f + ): BufferedImage { val width = sprite.width val height = sprite.height val image = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) @@ -86,11 +92,11 @@ object SpriteToBufferedImage { // Apply grayscale or tint if provided val finalColor = if (grayscale) { - applyGrayscale(Color(color, true)) + applyGrayscale(Color(color, true), brightnessBoost) } else if (tint != null) { - applyTint(Color(color, true), tint) + applyTint(Color(color, true), tint, brightnessBoost) } else { - Color(color, true) + applyBrightness(Color(color, true), brightnessBoost) } image.setRGB(x, y, finalColor.rgb) @@ -107,11 +113,11 @@ object SpriteToBufferedImage { // Apply grayscale or tint if provided val finalColor = if (grayscale) { - applyGrayscale(Color(color, true)) + applyGrayscale(Color(color, true), brightnessBoost) } else if (tint != null) { - applyTint(Color(color, true), tint) + applyTint(Color(color, true), tint, brightnessBoost) } else { - Color(color, true) + applyBrightness(Color(color, true), brightnessBoost) } image.setRGB(x, y, finalColor.rgb) @@ -127,32 +133,44 @@ object SpriteToBufferedImage { * Applies a tint to a given color using the tint's alpha value to control the intensity. * * @param original The original color. - * @param tint The tint color to be applied, with alpha controlling the intensity. + * @param tint The tint color to be applied. + * @param brightnessBoost A multiplier to boost the brightness of the image. * @return The tinted color. */ - fun applyTint(original: Color, tint: Color): Color { - val alpha = tint.alpha / 255.0 // Normalize alpha to range [0, 1] - val invAlpha = 1.0 - alpha - - // Blend the tint with the original color based on the alpha - val r = (original.red * invAlpha + tint.red * alpha).toInt().coerceIn(0, 255) - val g = (original.green * invAlpha + tint.green * alpha).toInt().coerceIn(0, 255) - val b = (original.blue * invAlpha + tint.blue * alpha).toInt().coerceIn(0, 255) + fun applyTint(original: Color, tint: Color, brightnessBoost: Float): Color { + val boostedColor = applyBrightness(original, brightnessBoost) + val r = (boostedColor.red * tint.red / 255).coerceIn(0, 255) + val g = (boostedColor.green * tint.green / 255).coerceIn(0, 255) + val b = (boostedColor.blue * tint.blue / 255).coerceIn(0, 255) + return Color(r, g, b, boostedColor.alpha) + } + /** + * Boosts the brightness of a given color. + * + * @param original The original color. + * @param factor The multiplier to boost the brightness. + * @return The color with boosted brightness. + */ + fun applyBrightness(original: Color, factor: Float): Color { + val r = (original.red * factor).coerceIn(0.0f, 255.0f).toInt() + val g = (original.green * factor).coerceIn(0.0f, 255.0f).toInt() + val b = (original.blue * factor).coerceIn(0.0f, 255.0f).toInt() return Color(r, g, b, original.alpha) } - /** - * Converts a color to grayscale. + * Converts a color to grayscale and applies a brightness boost. * * @param original The original color. - * @return The grayscale version of the color. + * @param brightnessBoost A multiplier to boost the brightness. + * @return The grayscale version of the color with boosted brightness. */ - fun applyGrayscale(original: Color): Color { + fun applyGrayscale(original: Color, brightnessBoost: Float): Color { // Calculate the grayscale value using the luminosity method val grayValue = (0.3 * original.red + 0.59 * original.green + 0.11 * original.blue).toInt() - return Color(grayValue, grayValue, grayValue, original.alpha) + val boostedGray = (grayValue * brightnessBoost).coerceIn(0.0f, 255.0f).toInt() + return Color(boostedGray, boostedGray, boostedGray, original.alpha) } /** @@ -161,14 +179,20 @@ object SpriteToBufferedImage { * @param sprite The sprite object to be converted. * @param tint An optional Color to tint the image. * @param grayscale If true, converts the image to grayscale. + * @param brightnessBoost A multiplier to boost the brightness of the image. * @return The BufferedImage created from the sprite or a default image if unsupported. */ - fun getBufferedImageFromSprite(sprite: Any?, tint: Color? = null, grayscale: Boolean = false): BufferedImage { + fun getBufferedImageFromSprite( + sprite: Any?, + tint: Color? = null, + grayscale: Boolean = false, + brightnessBoost: Float = 1.0f + ): BufferedImage { return when (sprite) { - is SoftwareSprite -> convertToBufferedImage(adaptSoftwareSprite(sprite), tint, grayscale) - is SoftwareIndexedSprite -> convertToBufferedImage(adaptSoftwareIndexedSprite(sprite), tint, grayscale) - is GlSprite -> convertToBufferedImage(adaptGlSprite(sprite), tint, grayscale) - is GlIndexedSprite -> convertToBufferedImage(adaptGlIndexedSprite(sprite), tint, grayscale) + is SoftwareSprite -> convertToBufferedImage(adaptSoftwareSprite(sprite), tint, grayscale, brightnessBoost) + is SoftwareIndexedSprite -> convertToBufferedImage(adaptSoftwareIndexedSprite(sprite), tint, grayscale, brightnessBoost) + is GlSprite -> convertToBufferedImage(adaptGlSprite(sprite), tint, grayscale, brightnessBoost) + is GlIndexedSprite -> convertToBufferedImage(adaptGlIndexedSprite(sprite), tint, grayscale, brightnessBoost) else -> BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB) // Default empty image for unsupported types } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/Themes.kt b/plugin-playground/src/main/kotlin/KondoKit/Themes.kt new file mode 100644 index 0000000..fc64103 --- /dev/null +++ b/plugin-playground/src/main/kotlin/KondoKit/Themes.kt @@ -0,0 +1,94 @@ +package KondoKit + +import java.awt.Color + +object Themes { + enum class ThemeType { + RUNELITE, + DARKER_RUNELITE, + SARADOMIN, + ORION, + } + + fun getTheme(themeType: ThemeType): Theme { + return when (themeType) { + ThemeType.RUNELITE -> Theme( + widgetColor = Color(30, 30, 30), + titleBarColor = Color(21, 21, 21), + viewBackgroundColor = Color(40, 40, 40), + primaryColor = Color(165, 165, 165), + secondaryColor = Color(255, 255, 255), + popupBackground = Color(45, 45, 45), + popupForeground = Color(220, 220, 220), + tooltipBackground = Color(50, 50, 50), + scrollBarColor = Color(64, 64, 64), + progressBarFill = Color(61, 56, 49), + navTint = null, + navGreyScale = false, + boost = 1f + ) + ThemeType.DARKER_RUNELITE -> Theme( + widgetColor = Color(15, 15, 15), + titleBarColor = Color(10, 10, 10), + viewBackgroundColor = Color(20, 20, 20), + primaryColor = Color(140, 140, 140), + secondaryColor = Color(210, 210, 210), + popupBackground = Color(25, 25, 25), + popupForeground = Color(200, 200, 200), + tooltipBackground = Color(30, 30, 30), + scrollBarColor = Color(40, 40, 40), + progressBarFill = Color(45, 40, 35), + navTint = null, + navGreyScale = false, + boost = 0.8f + ) + ThemeType.ORION -> Theme( + widgetColor = Color(50, 50, 50), + titleBarColor = Color(35, 35, 35), + viewBackgroundColor = Color(60, 60, 60), + primaryColor = Color(180, 180, 180), + secondaryColor = Color(210, 210, 210), + popupBackground = Color(45, 45, 45), + popupForeground = Color(230, 230, 230), + tooltipBackground = Color(55, 55, 55), + scrollBarColor = Color(75, 75, 75), + progressBarFill = Color(100, 100, 100), + navTint = null, + navGreyScale = true, + boost = 1.3f + ) + ThemeType.SARADOMIN -> Theme( + widgetColor = Color(62, 53, 41), + titleBarColor = Color(111, 93, 69).darker(), + viewBackgroundColor = Color(111, 93, 69), + primaryColor = Color(180, 150, 120), + secondaryColor = Color(230, 210, 190), + popupBackground = Color(70, 56, 42), + popupForeground = Color(220, 200, 180), + tooltipBackground = Color(80, 65, 50), + scrollBarColor = Color(100, 85, 70), + progressBarFill = Color(130, 110, 90), + navTint = null, + navGreyScale = false, + boost = 1f + ) + } + } + + + data class Theme( + val widgetColor: Color, + val titleBarColor: Color, + val viewBackgroundColor: Color, + val primaryColor: Color, + val secondaryColor: Color, + val popupBackground: Color, + val popupForeground: Color, + val tooltipBackground: Color, + val scrollBarColor: Color, + val progressBarFill: Color, + val navTint: Color?, + val navGreyScale: Boolean, + val boost: Float + ) +} diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index daf92c1..da70318 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -5,7 +5,6 @@ import KondoKit.Helpers.formatHtmlLabelText import KondoKit.Helpers.formatNumber import KondoKit.Helpers.getSpriteId import KondoKit.Helpers.showAlert -import KondoKit.Helpers.showToast import KondoKit.HiscoresView.createHiscoreSearchView import KondoKit.HiscoresView.hiScoreView import KondoKit.LootTrackerView.BAG_ICON @@ -18,6 +17,9 @@ import KondoKit.ReflectiveEditorView.addPlugins import KondoKit.ReflectiveEditorView.createReflectiveEditorView import KondoKit.ReflectiveEditorView.reflectiveEditorView import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite +import KondoKit.Themes.Theme +import KondoKit.Themes.ThemeType +import KondoKit.Themes.getTheme import KondoKit.XPTrackerView.createXPTrackerView import KondoKit.XPTrackerView.createXPWidget import KondoKit.XPTrackerView.initialXP @@ -28,7 +30,6 @@ import KondoKit.XPTrackerView.wrappedWidget import KondoKit.XPTrackerView.xpTrackerView import KondoKit.XPTrackerView.xpWidgets import KondoKit.plugin.StateManager.focusedView -import com.sun.org.apache.xpath.internal.operations.Bool import plugin.Plugin import plugin.api.* import plugin.api.API.* @@ -70,6 +71,7 @@ class plugin : Plugin() { var PROGRESS_BAR_FILL = Color(61, 56, 49) var NAV_TINT: Color? = null var NAV_GREYSCALE = false + var BOOST = 1f var appliedTheme = ThemeType.RUNELITE @@ -105,10 +107,10 @@ class plugin : Plugin() { private var pluginsReloaded = false private var loginScreen = 160 private var lastLogin = "" - private var initialized = false; + private var initialized = false private var lastClickTime = 0L private var lastUIOffset = 0 - private const val HIDDEN_VIEW = "HIDDEN"; + private const val HIDDEN_VIEW = "HIDDEN" private val drawActions = mutableListOf<() -> Unit>() fun registerDrawAction(action: () -> Unit) { @@ -123,19 +125,19 @@ class plugin : Plugin() { try{ for (i in 0 until 24) { if(!js5Archive8.isFileReady(getSpriteId(i))){ - return false; + return false } } - val otherIcons = arrayOf(LVL_ICON, MAG_SPRITE, LOOT_ICON, WRENCH_ICON, COMBAT_LVL_SPRITE, BAG_ICON); + val otherIcons = arrayOf(LVL_ICON, MAG_SPRITE, LOOT_ICON, WRENCH_ICON, COMBAT_LVL_SPRITE, BAG_ICON) for (icon in otherIcons) { if(!js5Archive8.isFileReady(icon)){ - return false; + return false } } } catch (e : Exception){ - return false; + return false } - return true; + return true } override fun OnLogin() { @@ -149,9 +151,9 @@ class plugin : Plugin() { override fun Init() { // Disable Font AA - System.setProperty("sun.java2d.opengl", "false"); - System.setProperty("awt.useSystemAAFontSettings", "off"); - System.setProperty("swing.aatext", "false"); + System.setProperty("sun.java2d.opengl", "false") + System.setProperty("awt.useSystemAAFontSettings", "off") + System.setProperty("swing.aatext", "false") } private fun UpdateDisplaySettings() { @@ -465,7 +467,7 @@ class plugin : Plugin() { } private fun createNavButton(spriteId: Int, viewName: String): JPanel { - val bufferedImageSprite = getBufferedImageFromSprite(GetSprite(spriteId), NAV_TINT, NAV_GREYSCALE) + val bufferedImageSprite = getBufferedImageFromSprite(GetSprite(spriteId), NAV_TINT, NAV_GREYSCALE, BOOST) val buttonSize = Dimension(NAVBAR_WIDTH, 32) val imageSize = Dimension((bufferedImageSprite.width / 1.2f).toInt(), (bufferedImageSprite.height / 1.2f).toInt()) val cooldownDuration = 100L @@ -581,89 +583,6 @@ class plugin : Plugin() { PROGRESS_BAR_FILL = theme.progressBarFill NAV_TINT = theme.navTint NAV_GREYSCALE = theme.navGreyScale + BOOST = theme.boost } - - enum class ThemeType { - RUNELITE, - DARKER_RUNELITE, - SARADOMIN, - ORION, - } - - fun getTheme(themeType: ThemeType): Theme { - return when (themeType) { - ThemeType.RUNELITE -> Theme( - widgetColor = Color(30, 30, 30), - titleBarColor = Color(21, 21, 21), - viewBackgroundColor = Color(40, 40, 40), - primaryColor = Color(165, 165, 165), - secondaryColor = Color(255, 255, 255), - popupBackground = Color(45, 45, 45), - popupForeground = Color(220, 220, 220), - tooltipBackground = Color(50, 50, 50), - scrollBarColor = Color(64, 64, 64), - progressBarFill = Color(61, 56, 49), - navTint = null, - navGreyScale = false - ) - ThemeType.DARKER_RUNELITE -> Theme( - widgetColor = Color(15, 15, 15), // Darker widget backgrounds - titleBarColor = Color(10, 10, 10), // Even darker title bar - viewBackgroundColor = Color(20, 20, 20), // Very dark background for the view - primaryColor = Color(140, 140, 140), // Darker shade for primary text - secondaryColor = Color(210, 210, 210), // Slightly muted white for secondary text - popupBackground = Color(25, 25, 25), // Very dark popup backgrounds - popupForeground = Color(200, 200, 200), // Slightly muted light gray for popup text - tooltipBackground = Color(30, 30, 30), // Darker tooltips background - scrollBarColor = Color(40, 40, 40), // Darker scroll bar - progressBarFill = Color(45, 40, 35), // Darker progress bar fill - navTint = null, //Color(20, 20, 20, 60), // No specific tint applied - navGreyScale = false // Navigation retains color (if applicable) - ) - ThemeType.ORION -> Theme( - widgetColor = Color(50, 50, 50), // Darker gray for widget backgrounds - titleBarColor = Color(35, 35, 35), // Very dark gray for the title bar - viewBackgroundColor = Color(60, 60, 60), // Medium-dark gray for view background - primaryColor = Color(180, 180, 180), // Lighter gray for primary text or highlights - secondaryColor = Color(210, 210, 210), // Light gray for secondary text - popupBackground = Color(45, 45, 45), // Dark gray for popup backgrounds - popupForeground = Color(230, 230, 230), // Light gray for popup text - tooltipBackground = Color(55, 55, 55), // Slightly darker gray for tooltips - scrollBarColor = Color(75, 75, 75), // Dark gray for scroll bars - progressBarFill = Color(100, 100, 100), // Medium gray for progress bar fill - navTint = null, - navGreyScale = true - ) - ThemeType.SARADOMIN -> Theme( - widgetColor = Color(75, 60, 45), - titleBarColor = Color(60, 48, 36), - viewBackgroundColor = Color(95, 76, 58), - primaryColor = Color(180, 150, 120), - secondaryColor = Color(230, 210, 190), - popupBackground = Color(70, 56, 42), - popupForeground = Color(220, 200, 180), - tooltipBackground = Color(80, 65, 50), - scrollBarColor = Color(100, 85, 70), - progressBarFill = Color(130, 110, 90), - navTint = null, - navGreyScale = false - ) - } - } - - - data class Theme( - val widgetColor: Color, - val titleBarColor: Color, - val viewBackgroundColor: Color, - val primaryColor: Color, - val secondaryColor: Color, - val popupBackground: Color, - val popupForeground: Color, - val tooltipBackground: Color, - val scrollBarColor: Color, - val progressBarFill: Color, - val navTint: Color?, - val navGreyScale: Boolean - ) } From fce9b4eea7991eedfbd9e986e0f7c94a742a41d3 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Wed, 23 Oct 2024 14:44:32 -0700 Subject: [PATCH 19/47] AWT native component theming --- .../kotlin/KondoKit/ReflectiveEditorView.kt | 2 +- .../src/main/kotlin/KondoKit/plugin.kt | 64 ++++++++++++++----- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt index cd167c9..60deccf 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt @@ -207,7 +207,7 @@ object ReflectiveEditorView { fieldPanel.add(inputComponent, gbc) val applyButton = JButton("\u2714").apply { - maximumSize = Dimension(Int.MAX_VALUE, 10) + maximumSize = Dimension(Int.MAX_VALUE, 8) } gbc.gridx = 2 gbc.gridy = 0 diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index da70318..bc0f6b3 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -46,6 +46,7 @@ import java.awt.event.ActionListener import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import javax.swing.* +import javax.swing.plaf.nimbus.AbstractRegionPainter @Target(AnnotationTarget.FIELD) @@ -327,21 +328,54 @@ class plugin : Plugin() { try { UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel") - // Modify the UI properties for a dark theme - UIManager.put("control", Color(50, 50, 50)) // Default background for most controls - UIManager.put("info", Color(50, 50, 50)) - UIManager.put("nimbusBase", Color(35, 35, 35)) // Base color for Nimbus L&F - UIManager.put("nimbusAlertYellow", Color(255, 220, 35)) - UIManager.put("nimbusDisabledText", Color(100, 100, 100)) - UIManager.put("nimbusFocus", Color(115, 164, 209)) - UIManager.put("nimbusGreen", Color(176, 179, 50)) - UIManager.put("nimbusInfoBlue", Color(66, 139, 221)) - UIManager.put("nimbusLightBackground", Color(35, 35, 35)) // Background of text fields, etc. - UIManager.put("nimbusOrange", Color(191, 98, 4)) - UIManager.put("nimbusRed", Color(169, 46, 34)) - UIManager.put("nimbusSelectedText", Color(255, 255, 255)) - UIManager.put("nimbusSelectionBackground", Color(75, 110, 175)) // Selection background - UIManager.put("text", Color(230, 230, 230)) // General text color + // Modify the UI properties to match theme + UIManager.put("control", VIEW_BACKGROUND_COLOR) + UIManager.put("info", VIEW_BACKGROUND_COLOR) + UIManager.put("nimbusBase", WIDGET_COLOR) + UIManager.put("nimbusBlueGrey", TITLE_BAR_COLOR) + + UIManager.put("nimbusDisabledText", primaryColor) + UIManager.put("nimbusSelectedText", secondaryColor) + UIManager.put("text", secondaryColor) + + UIManager.put("nimbusFocus", TITLE_BAR_COLOR) + UIManager.put("nimbusInfoBlue", POPUP_BACKGROUND) + UIManager.put("nimbusLightBackground", WIDGET_COLOR) + UIManager.put("nimbusSelectionBackground", PROGRESS_BAR_FILL) + + UIManager.put("Button.background", WIDGET_COLOR) + UIManager.put("Button.foreground", secondaryColor) + + UIManager.put("CheckBox.background", VIEW_BACKGROUND_COLOR) + UIManager.put("CheckBox.foreground", secondaryColor) + UIManager.put("CheckBox.icon", UIManager.getIcon("CheckBox.icon")) + + UIManager.put("ComboBox.background", WIDGET_COLOR) + UIManager.put("ComboBox.foreground", secondaryColor) + UIManager.put("ComboBox.selectionBackground", PROGRESS_BAR_FILL) + UIManager.put("ComboBox.selectionForeground", primaryColor) + UIManager.put("ComboBox.buttonBackground", WIDGET_COLOR) + + UIManager.put("Spinner.background", WIDGET_COLOR) + UIManager.put("Spinner.foreground", secondaryColor) + UIManager.put("Spinner.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) + + UIManager.put("TextField.background", WIDGET_COLOR) + UIManager.put("TextField.foreground", secondaryColor) + UIManager.put("TextField.caretForeground", secondaryColor) + UIManager.put("TextField.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) + + UIManager.put("ScrollBar.thumb", WIDGET_COLOR) + UIManager.put("ScrollBar.track", VIEW_BACKGROUND_COLOR) + UIManager.put("ScrollBar.thumbHighlight", TITLE_BAR_COLOR) + + UIManager.put("ProgressBar.foreground", PROGRESS_BAR_FILL) + UIManager.put("ProgressBar.background", WIDGET_COLOR) + UIManager.put("ProgressBar.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) + + UIManager.put("ToolTip.background", VIEW_BACKGROUND_COLOR) + UIManager.put("ToolTip.foreground", secondaryColor) + UIManager.put("ToolTip.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) // Update component tree UI to apply the new theme SwingUtilities.updateComponentTreeUI(GameShell.frame) From c917981ef82b911aab65b554c5f67ca276de99e5 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Wed, 23 Oct 2024 15:59:29 -0700 Subject: [PATCH 20/47] Additional theme support + dynamic scrolling for resized views --- .../src/main/kotlin/KondoKit/ScrollablePanel.kt | 6 +++++- plugin-playground/src/main/kotlin/KondoKit/Themes.kt | 2 +- plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt index 46f2b5a..cf6444c 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt @@ -17,6 +17,7 @@ class ScrollablePanel(private val content: JPanel) : JPanel() { private var scrollbarY = 0 private var showScrollbar = false private var draggingScrollPill = false + private var lastSize = 0 // Define a buffer for the view height (extra space for smoother scrolling) private val viewBuffer = -30 @@ -68,6 +69,8 @@ class ScrollablePanel(private val content: JPanel) : JPanel() { Timer().schedule(object : TimerTask() { override fun run() { updateScrollbar() + if(lastSize != content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer)) + handleResize() } }, 0, 1000) @@ -84,7 +87,8 @@ class ScrollablePanel(private val content: JPanel) : JPanel() { bounds = Rectangle(0, 0, 242, frame.height) // Dynamically update content bounds and scrollbar on frame resize with buffer - content.bounds = Rectangle(0, 0, 242, content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer)) + lastSize = content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer) + content.bounds = Rectangle(0, 0, 242, lastSize) showScrollbar = content.height > frame.height currentOffsetY = 0 diff --git a/plugin-playground/src/main/kotlin/KondoKit/Themes.kt b/plugin-playground/src/main/kotlin/KondoKit/Themes.kt index fc64103..1b7988d 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/Themes.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/Themes.kt @@ -60,7 +60,7 @@ object Themes { ThemeType.SARADOMIN -> Theme( widgetColor = Color(62, 53, 41), titleBarColor = Color(111, 93, 69).darker(), - viewBackgroundColor = Color(111, 93, 69), + viewBackgroundColor = Color(101, 85, 63), primaryColor = Color(180, 150, 120), secondaryColor = Color(230, 210, 190), popupBackground = Color(70, 56, 42), diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index bc0f6b3..1fde673 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -46,7 +46,6 @@ import java.awt.event.ActionListener import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import javax.swing.* -import javax.swing.plaf.nimbus.AbstractRegionPainter @Target(AnnotationTarget.FIELD) From 668345b81e1713a21e1f0a29bbe6fbcfe228624c Mon Sep 17 00:00:00 2001 From: downthecrop Date: Thu, 24 Oct 2024 12:03:16 -0700 Subject: [PATCH 21/47] FIXED streched mode --- client/src/main/java/plugin/Plugin.java | 15 ++ .../main/java/plugin/PluginRepository.java | 5 + client/src/main/java/rt4/FrameBuffer.java | 2 +- client/src/main/java/rt4/client.java | 1 + .../src/main/kotlin/KondoKit/plugin.kt | 176 +++++++++++++++++- 5 files changed, 191 insertions(+), 8 deletions(-) diff --git a/client/src/main/java/plugin/Plugin.java b/client/src/main/java/plugin/Plugin.java index 7a4a039..e8e3641 100644 --- a/client/src/main/java/plugin/Plugin.java +++ b/client/src/main/java/plugin/Plugin.java @@ -13,6 +13,7 @@ import rt4.Tile; */ public abstract class Plugin { long timeOfLastDraw; + long timeOfLastLateDraw; void _init() { Init(); @@ -24,6 +25,12 @@ public abstract class Plugin { timeOfLastDraw = nowTime; } + void _lateDraw() { + long nowTime = System.currentTimeMillis(); + LateDraw(nowTime - timeOfLastLateDraw); + timeOfLastLateDraw = nowTime; + } + /** * Draw() is called by the client rendering loop so that plugins can draw information onto the screen. * This will be called once per frame, meaning it is framerate bound. @@ -31,6 +38,14 @@ public abstract class Plugin { */ public void Draw(long timeDelta) {} + + /** + * LateDraw() is called at the end of a finalized frame + * This will be called once per frame, meaning it is framerate bound. + * @param timeDelta the time (ms) elapsed since the last draw call. + */ + public void LateDraw(long timeDelta) {} + /** * Init() is called when the plugin is first loaded */ diff --git a/client/src/main/java/plugin/PluginRepository.java b/client/src/main/java/plugin/PluginRepository.java index 2af27f6..55faf80 100644 --- a/client/src/main/java/plugin/PluginRepository.java +++ b/client/src/main/java/plugin/PluginRepository.java @@ -160,6 +160,11 @@ public class PluginRepository { pluginsSnapshot.forEach(Plugin::_draw); } + public static void LateDraw() { + List pluginsSnapshot = new ArrayList<>(loadedPlugins.values()); + pluginsSnapshot.forEach(Plugin::_lateDraw); + } + public static void NPCOverheadDraw(Npc npc, int screenX, int screenY) { loadedPlugins.values().forEach((plugin) -> plugin.NPCOverheadDraw(npc, screenX, screenY)); } diff --git a/client/src/main/java/rt4/FrameBuffer.java b/client/src/main/java/rt4/FrameBuffer.java index 5999c44..f641434 100644 --- a/client/src/main/java/rt4/FrameBuffer.java +++ b/client/src/main/java/rt4/FrameBuffer.java @@ -12,7 +12,7 @@ import java.awt.*; public abstract class FrameBuffer { @OriginalMember(owner = "client!vk", name = "e", descriptor = "[I") - protected int[] pixels; + public int[] pixels; @OriginalMember(owner = "client!vk", name = "g", descriptor = "Ljava/awt/Image;") protected Image image; diff --git a/client/src/main/java/rt4/client.java b/client/src/main/java/rt4/client.java index 34adc87..7a77445 100644 --- a/client/src/main/java/rt4/client.java +++ b/client/src/main/java/rt4/client.java @@ -921,6 +921,7 @@ public final class client extends GameShell { Preferences.safeMode = false; Preferences.write(GameShell.signLink); } + PluginRepository.LateDraw(); } @OriginalMember(owner = "client!client", name = "c", descriptor = "(B)V") diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index bc0f6b3..f4a604f 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -35,16 +35,17 @@ import plugin.api.* import plugin.api.API.* import plugin.api.FontColor.fromColor import rt4.GameShell +import rt4.GameShell.canvas import rt4.GameShell.frame import rt4.GlRenderer import rt4.InterfaceList import rt4.Player +import rt4.SoftwareRaster import rt4.client.js5Archive8 import rt4.client.mainLoadState import java.awt.* -import java.awt.event.ActionListener -import java.awt.event.MouseAdapter -import java.awt.event.MouseEvent +import java.awt.event.* +import java.awt.image.BufferedImage import javax.swing.* import javax.swing.plaf.nimbus.AbstractRegionPainter @@ -149,12 +150,157 @@ class plugin : Plugin() { } lastLogin = Player.usernameInput.toString() } + class AltCanvas(private val mainCanvas: Canvas) : JPanel() { + private var gameImage: BufferedImage? = null + private var scaleX = 1.0 + private var scaleY = 1.0 + private var offsetX = 0 + private var offsetY = 0 + init { + gameImage = BufferedImage(765, 503, BufferedImage.TYPE_INT_ARGB) + val g = gameImage!!.createGraphics() + g.color = Color.RED + g.fillRect(0, 0, gameImage!!.width, gameImage!!.height) + g.color = Color.BLACK + g.drawString("Game Frame", 20, 20) + g.dispose() + + addMouseListener(object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) { + relayMouseEvent(e) + } + + override fun mouseReleased(e: MouseEvent) { + relayMouseEvent(e) + } + + override fun mouseClicked(e: MouseEvent) { + relayMouseEvent(e) + } + }) + + addMouseMotionListener(object : MouseMotionAdapter() { + override fun mouseMoved(e: MouseEvent) { + relayMouseEvent(e) + } + + override fun mouseDragged(e: MouseEvent) { + relayMouseEvent(e) + } + }) + + // Register a KeyAdapter for handling key events + addKeyListener(object : KeyAdapter() { + override fun keyPressed(e: KeyEvent) { + for(listener in canvas.keyListeners){ + listener.keyPressed(e) + } + } + + override fun keyReleased(e: KeyEvent) { + for(listener in canvas.keyListeners){ + listener.keyReleased(e) + } + } + + override fun keyTyped(e: KeyEvent) { + for(listener in canvas.keyListeners){ + listener.keyTyped(e) + } + } + }) + + isFocusable = true + requestFocusInWindow() + } + + override fun paintComponent(g: Graphics) { + super.paintComponent(g) + val g2d = g as Graphics2D + + // Set the desired background fill color here + g2d.color = Color(30, 30, 30) // Replace with your preferred fill color + g2d.fillRect(0, 0, width, height) + gameImage?.let { image -> + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) + + // Calculate aspect-ratio-preserving scale + val imageAspect = image.width.toDouble() / image.height.toDouble() + val panelAspect = width.toDouble() / height.toDouble() + + val (drawWidth, drawHeight) = if (imageAspect > panelAspect) { + val newWidth = width + val newHeight = (width / imageAspect).toInt() + newWidth to newHeight + } else { + val newHeight = height + val newWidth = (height * imageAspect).toInt() + newWidth to newHeight + } + + // Store scale factors and offsets for event adjustment + scaleX = drawWidth.toDouble() / image.width + scaleY = drawHeight.toDouble() / image.height + offsetX = (width - drawWidth) / 2 + offsetY = (height - drawHeight) / 2 + + // Draw the scaled image centered in the panel + val x = offsetX + val y = offsetY + g2d.drawImage(image, x, y, drawWidth, drawHeight, null) + } + } + + private fun relayMouseEvent(e: MouseEvent) { + val adjustedX = (e.x - offsetX) / scaleX + val adjustedY = (e.y - offsetY) / scaleY + + val originalX = adjustedX.toInt().coerceIn(0, gameImage!!.width - 1) + val originalY = adjustedY.toInt().coerceIn(0, gameImage!!.height - 1) + + val newEvent = MouseEvent( + mainCanvas, e.id, e.`when`, e.modifiersEx, + originalX, originalY, e.clickCount, e.isPopupTrigger, e.button + ) + + mainCanvas.dispatchEvent(newEvent) + } + + fun updateGameImage(newImage: BufferedImage) { + gameImage = newImage + repaint() + } + } + + + + fun createAltCanvas(mainCanvas: Canvas): AltCanvas { + return AltCanvas(mainCanvas).apply { + preferredSize = Dimension(FIXED_WIDTH, 503) + } + } + + private var altCanvas: AltCanvas? = null override fun Init() { // Disable Font AA System.setProperty("sun.java2d.opengl", "false") System.setProperty("awt.useSystemAAFontSettings", "off") System.setProperty("swing.aatext", "false") + val frame: Frame? = GameShell.frame + if (frame != null) { + // Create the AltCanvas and add it to the main frame + altCanvas = createAltCanvas(canvas) + + // Use BorderLayout for better layout control + frame.layout = BorderLayout() + + // Add the AltCanvas in the center to ensure it scales properly with the window size + frame.add(altCanvas, BorderLayout.NORTH) + frame.remove(canvas) + //frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE + frame.isVisible = true + } } private fun UpdateDisplaySettings() { @@ -166,9 +312,8 @@ class plugin : Plugin() { if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + uiOffset) { frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + uiOffset, frame.height) } - - val difference = frame.width - (FIXED_WIDTH + uiOffset + currentScrollPaneWidth) - GameShell.leftMargin = difference / 2 + val difference = frame.width - (uiOffset + currentScrollPaneWidth) + altCanvas?.size = Dimension(difference, frame.height - 30) } WindowMode.RESIZABLE -> { GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + uiOffset) @@ -274,7 +419,7 @@ class plugin : Plugin() { } } - override fun Draw(timeDelta: Long) { + override fun LateDraw(timeDelta: Long) { if (GlRenderer.enabled && GlRenderer.canvasWidth != GameShell.canvasWidth) { GlRenderer.canvasWidth = GameShell.canvasWidth GlRenderer.setViewportBounds(0, 0, GameShell.canvasWidth, GameShell.canvasHeight) @@ -296,6 +441,10 @@ class plugin : Plugin() { accumulatedTime = 0L } + // Update game image here + val rasterImage = getRasterImageFromGameShell() // Replace this with the actual method to fetch the BufferedImage from GameShell.canvas. + altCanvas?.updateGameImage(rasterImage) + // Draw synced actions (that require to be done between glBegin and glEnd) if (drawActions.isNotEmpty()) { synchronized(drawActions) { @@ -313,6 +462,18 @@ class plugin : Plugin() { } } + // Placeholder method to get the game image from GameShell + fun getRasterImageFromGameShell(): BufferedImage { + // Assuming SoftwareRaster.pixels is an IntArray containing ARGB values of the game image. + val gameImage = BufferedImage(765, 503, BufferedImage.TYPE_INT_ARGB) + + val g = gameImage.createGraphics() + + SoftwareRaster.frameBuffer.draw(g) + return gameImage + } + + private fun initKondoUI(){ DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) if(!allSpritesLoaded()) return; @@ -379,6 +540,7 @@ class plugin : Plugin() { // Update component tree UI to apply the new theme SwingUtilities.updateComponentTreeUI(GameShell.frame) + GameShell.frame.background = Color.BLACK } catch (e : Exception) { e.printStackTrace() } From 8e554b573c7d604871e344513124d21864cad731 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Thu, 24 Oct 2024 20:24:40 -0700 Subject: [PATCH 22/47] gather functions together for easier debugging --- .../src/main/kotlin/KondoKit/plugin.kt | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index f4a604f..5a6526c 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -220,7 +220,7 @@ class plugin : Plugin() { val g2d = g as Graphics2D // Set the desired background fill color here - g2d.color = Color(30, 30, 30) // Replace with your preferred fill color + g2d.color = Color.BLACK g2d.fillRect(0, 0, width, height) gameImage?.let { image -> g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) @@ -273,15 +273,25 @@ class plugin : Plugin() { } } - - fun createAltCanvas(mainCanvas: Canvas): AltCanvas { return AltCanvas(mainCanvas).apply { preferredSize = Dimension(FIXED_WIDTH, 503) } } + fun getRasterImageFromGameShell(): BufferedImage { + // Assuming SoftwareRaster.pixels is an IntArray containing ARGB values of the game image. + val gameImage = BufferedImage(765, 503, BufferedImage.TYPE_INT_ARGB) + + val g = gameImage.createGraphics() + + SoftwareRaster.frameBuffer.draw(g) + return gameImage + } + private var altCanvas: AltCanvas? = null + + override fun Init() { // Disable Font AA System.setProperty("sun.java2d.opengl", "false") @@ -296,10 +306,8 @@ class plugin : Plugin() { frame.layout = BorderLayout() // Add the AltCanvas in the center to ensure it scales properly with the window size - frame.add(altCanvas, BorderLayout.NORTH) + altCanvas?.let { frame.add(it, BorderLayout.NORTH) } frame.remove(canvas) - //frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE - frame.isVisible = true } } @@ -442,7 +450,7 @@ class plugin : Plugin() { } // Update game image here - val rasterImage = getRasterImageFromGameShell() // Replace this with the actual method to fetch the BufferedImage from GameShell.canvas. + val rasterImage = getRasterImageFromGameShell() altCanvas?.updateGameImage(rasterImage) // Draw synced actions (that require to be done between glBegin and glEnd) @@ -462,18 +470,6 @@ class plugin : Plugin() { } } - // Placeholder method to get the game image from GameShell - fun getRasterImageFromGameShell(): BufferedImage { - // Assuming SoftwareRaster.pixels is an IntArray containing ARGB values of the game image. - val gameImage = BufferedImage(765, 503, BufferedImage.TYPE_INT_ARGB) - - val g = gameImage.createGraphics() - - SoftwareRaster.frameBuffer.draw(g) - return gameImage - } - - private fun initKondoUI(){ DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) if(!allSpritesLoaded()) return; From af4dafee893bfe8fd621b3ce067271b66a83f491 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Thu, 24 Oct 2024 20:50:56 -0700 Subject: [PATCH 23/47] Convert to volatile and centralize logic to the altcanvas. --- .../src/main/kotlin/KondoKit/plugin.kt | 84 ++++++++++++------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 5a6526c..bc550e3 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -45,7 +45,7 @@ import rt4.client.js5Archive8 import rt4.client.mainLoadState import java.awt.* import java.awt.event.* -import java.awt.image.BufferedImage +import java.awt.image.VolatileImage import javax.swing.* import javax.swing.plaf.nimbus.AbstractRegionPainter @@ -151,20 +151,15 @@ class plugin : Plugin() { lastLogin = Player.usernameInput.toString() } class AltCanvas(private val mainCanvas: Canvas) : JPanel() { - private var gameImage: BufferedImage? = null + private var gameImage: VolatileImage? = null private var scaleX = 1.0 private var scaleY = 1.0 private var offsetX = 0 private var offsetY = 0 + init { - gameImage = BufferedImage(765, 503, BufferedImage.TYPE_INT_ARGB) - val g = gameImage!!.createGraphics() - g.color = Color.RED - g.fillRect(0, 0, gameImage!!.width, gameImage!!.height) - g.color = Color.BLACK - g.drawString("Game Frame", 20, 20) - g.dispose() + validateGameImage() addMouseListener(object : MouseAdapter() { override fun mousePressed(e: MouseEvent) { @@ -193,26 +188,55 @@ class plugin : Plugin() { // Register a KeyAdapter for handling key events addKeyListener(object : KeyAdapter() { override fun keyPressed(e: KeyEvent) { - for(listener in canvas.keyListeners){ + for (listener in mainCanvas.keyListeners) { listener.keyPressed(e) } } override fun keyReleased(e: KeyEvent) { - for(listener in canvas.keyListeners){ + for (listener in mainCanvas.keyListeners) { listener.keyReleased(e) } } override fun keyTyped(e: KeyEvent) { - for(listener in canvas.keyListeners){ + for (listener in mainCanvas.keyListeners) { listener.keyTyped(e) } } }) isFocusable = true - requestFocusInWindow() + } + + private fun validateGameImage() { + val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration + if (gameImage == null) { + gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.TRANSLUCENT) + renderGameImage() + } else { + val status = gameImage!!.validate(gc) + if (status == VolatileImage.IMAGE_INCOMPATIBLE) { + gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.TRANSLUCENT) + renderGameImage() + } else if (status == VolatileImage.IMAGE_RESTORED) { + renderGameImage() + } + } + } + + private fun renderGameImage() { + val g = gameImage!!.createGraphics() + try { + // Initial drawing code + g.color = Color.RED + g.fillRect(0, 0, gameImage!!.width, gameImage!!.height) + g.color = Color.BLACK + g.drawString("Game Frame", 20, 20) + // Add any additional rendering here + } finally { + g.dispose() + } } override fun paintComponent(g: Graphics) { @@ -222,6 +246,9 @@ class plugin : Plugin() { // Set the desired background fill color here g2d.color = Color.BLACK g2d.fillRect(0, 0, width, height) + + validateGameImage() + gameImage?.let { image -> g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) @@ -267,8 +294,14 @@ class plugin : Plugin() { mainCanvas.dispatchEvent(newEvent) } - fun updateGameImage(newImage: BufferedImage) { - gameImage = newImage + fun updateGameImage() { + validateGameImage() + val g = gameImage!!.createGraphics() + try { + SoftwareRaster.frameBuffer.draw(g) + } finally { + g.dispose() + } repaint() } } @@ -279,16 +312,6 @@ class plugin : Plugin() { } } - fun getRasterImageFromGameShell(): BufferedImage { - // Assuming SoftwareRaster.pixels is an IntArray containing ARGB values of the game image. - val gameImage = BufferedImage(765, 503, BufferedImage.TYPE_INT_ARGB) - - val g = gameImage.createGraphics() - - SoftwareRaster.frameBuffer.draw(g) - return gameImage - } - private var altCanvas: AltCanvas? = null @@ -427,7 +450,7 @@ class plugin : Plugin() { } } - override fun LateDraw(timeDelta: Long) { + override fun Draw(timeDelta: Long) { if (GlRenderer.enabled && GlRenderer.canvasWidth != GameShell.canvasWidth) { GlRenderer.canvasWidth = GameShell.canvasWidth GlRenderer.setViewportBounds(0, 0, GameShell.canvasWidth, GameShell.canvasHeight) @@ -449,10 +472,6 @@ class plugin : Plugin() { accumulatedTime = 0L } - // Update game image here - val rasterImage = getRasterImageFromGameShell() - altCanvas?.updateGameImage(rasterImage) - // Draw synced actions (that require to be done between glBegin and glEnd) if (drawActions.isNotEmpty()) { synchronized(drawActions) { @@ -470,6 +489,11 @@ class plugin : Plugin() { } } + override fun LateDraw(timeDelta: Long){ + // Update game image here + altCanvas?.updateGameImage() + } + private fun initKondoUI(){ DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) if(!allSpritesLoaded()) return; From 1eb7483d3561dd80d3623c32d37e0ba7b2138ccd Mon Sep 17 00:00:00 2001 From: downthecrop Date: Thu, 24 Oct 2024 20:58:45 -0700 Subject: [PATCH 24/47] Regain focus on click --- plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index bc550e3..a1b5137 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -41,13 +41,11 @@ import rt4.GlRenderer import rt4.InterfaceList import rt4.Player import rt4.SoftwareRaster -import rt4.client.js5Archive8 -import rt4.client.mainLoadState +import rt4.client.* import java.awt.* import java.awt.event.* import java.awt.image.VolatileImage import javax.swing.* -import javax.swing.plaf.nimbus.AbstractRegionPainter @Target(AnnotationTarget.FIELD) @@ -207,6 +205,7 @@ class plugin : Plugin() { }) isFocusable = true + requestFocusInWindow() } private fun validateGameImage() { @@ -280,6 +279,7 @@ class plugin : Plugin() { } private fun relayMouseEvent(e: MouseEvent) { + this.requestFocusInWindow() val adjustedX = (e.x - offsetX) / scaleX val adjustedY = (e.y - offsetY) / scaleY From 838acc57ff5cd447f35012083fb57df2ba90f646 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Thu, 24 Oct 2024 23:21:55 -0700 Subject: [PATCH 25/47] handing for altcanvas in alerts --- plugin-playground/src/main/kotlin/KondoKit/Helpers.kt | 2 +- plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt index bfcac22..67530e3 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt @@ -68,7 +68,7 @@ object Helpers { // Adjust for parent component location if it exists - if (parentComponent != null) { + if (parentComponent != null && GameShell.canvas.isShowing) { val parentLocation = parentComponent.locationOnScreen val x = parentLocation.x val y = GameShell.canvas.locationOnScreen.y diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index a1b5137..6e1adbb 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -324,7 +324,7 @@ class plugin : Plugin() { if (frame != null) { // Create the AltCanvas and add it to the main frame altCanvas = createAltCanvas(canvas) - + canvas.isVisible = false // Use BorderLayout for better layout control frame.layout = BorderLayout() From b3c2adc51f1c4af2a93269f5a6c2eadc5b1951fa Mon Sep 17 00:00:00 2001 From: downthecrop Date: Fri, 25 Oct 2024 15:54:39 -0700 Subject: [PATCH 26/47] support scaled fixed HD --- client/src/main/java/rt4/DisplayMode.java | 6 ++ client/src/main/java/rt4/GameShell.java | 1 + client/src/main/java/rt4/GlRenderer.java | 15 +++- .../src/main/kotlin/KondoKit/plugin.kt | 87 +++++++++++++++---- 4 files changed, 88 insertions(+), 21 deletions(-) diff --git a/client/src/main/java/rt4/DisplayMode.java b/client/src/main/java/rt4/DisplayMode.java index 440e79d..58bf779 100644 --- a/client/src/main/java/rt4/DisplayMode.java +++ b/client/src/main/java/rt4/DisplayMode.java @@ -79,6 +79,12 @@ public final class DisplayMode { @OriginalMember(owner = "client!pm", name = "a", descriptor = "(ZIZIZII)V") public static void setWindowMode(@OriginalArg(0) boolean replaceCanvas, @OriginalArg(1) int newMode, @OriginalArg(2) boolean useHD, @OriginalArg(3) int currentMode, @OriginalArg(5) int width, @OriginalArg(6) int height) { + if(!GameShell.canvas.isShowing()){ + GameShell.frame.add(GameShell.canvas); + GameShell.canvas.revalidate(); + GameShell.frame.revalidate(); + GameShell.canvas.repaint(); + } if (useHD) { GlRenderer.quit(); } diff --git a/client/src/main/java/rt4/GameShell.java b/client/src/main/java/rt4/GameShell.java index 80a799d..9bd0bd6 100644 --- a/client/src/main/java/rt4/GameShell.java +++ b/client/src/main/java/rt4/GameShell.java @@ -323,6 +323,7 @@ public abstract class GameShell extends Applet implements Runnable, FocusListene @OriginalMember(owner = "client!rc", name = "b", descriptor = "(B)V") public final synchronized void addCanvas() { if (canvas != null) { + // Remove the old canvas if it exists canvas.removeFocusListener(this); canvas.getParent().remove(canvas); } diff --git a/client/src/main/java/rt4/GlRenderer.java b/client/src/main/java/rt4/GlRenderer.java index b42e0de..c7a7d2a 100644 --- a/client/src/main/java/rt4/GlRenderer.java +++ b/client/src/main/java/rt4/GlRenderer.java @@ -24,6 +24,8 @@ public final class GlRenderer { public static float hFOV = 0; + public static int[] pixelData = null; + @OriginalMember(owner = "client!tf", name = "c", descriptor = "F") private static float aFloat30; @@ -67,7 +69,7 @@ public final class GlRenderer { private static int maxTextureCoords; @OriginalMember(owner = "client!tf", name = "E", descriptor = "Lgl!javax/media/opengl/GLDrawable;") - private static GLDrawable drawable; + public static GLDrawable drawable; @OriginalMember(owner = "client!tf", name = "H", descriptor = "Z") public static boolean arbVertexProgramSupported; @@ -199,11 +201,20 @@ public final class GlRenderer { @OriginalMember(owner = "client!tf", name = "d", descriptor = "()V") public static void swapBuffers() { try { + pixelData = readPixels(); drawable.swapBuffers(); - } catch (@Pc(3) Exception local3) { + } catch (@Pc(3) Exception local3) {*, } } + @OriginalMember(owner = "client!tf", name = "readPixels", descriptor = "()int[]") + public static int[] readPixels() { + int[] pixels = new int[canvasWidth * canvasHeight]; + IntBuffer buffer = IntBuffer.wrap(pixels); + gl.glReadPixels(0, 0, canvasWidth, canvasHeight, GL2.GL_BGRA, GlRenderer.bigEndian ? GL2.GL_UNSIGNED_INT_8_8_8_8_REV : GL2.GL_UNSIGNED_BYTE, buffer); + return pixels; + } + @OriginalMember(owner = "client!tf", name = "a", descriptor = "(Z)V") public static void setFogEnabled(@OriginalArg(0) boolean enabled) { if (enabled == fogEnabled) { diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 6e1adbb..983576d 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -34,17 +34,18 @@ import plugin.Plugin import plugin.api.* import plugin.api.API.* import plugin.api.FontColor.fromColor -import rt4.GameShell +import rt4.* import rt4.GameShell.canvas import rt4.GameShell.frame -import rt4.GlRenderer -import rt4.InterfaceList -import rt4.Player -import rt4.SoftwareRaster -import rt4.client.* +import rt4.client.js5Archive8 +import rt4.client.mainLoadState import java.awt.* +import java.awt.Font import java.awt.event.* +import java.awt.image.BufferedImage import java.awt.image.VolatileImage +import java.util.* +import java.util.Timer import javax.swing.* @@ -148,7 +149,7 @@ class plugin : Plugin() { } lastLogin = Player.usernameInput.toString() } - class AltCanvas(private val mainCanvas: Canvas) : JPanel() { + class AltCanvas() : JPanel() { private var gameImage: VolatileImage? = null private var scaleX = 1.0 private var scaleY = 1.0 @@ -186,19 +187,19 @@ class plugin : Plugin() { // Register a KeyAdapter for handling key events addKeyListener(object : KeyAdapter() { override fun keyPressed(e: KeyEvent) { - for (listener in mainCanvas.keyListeners) { + for (listener in canvas.keyListeners) { listener.keyPressed(e) } } override fun keyReleased(e: KeyEvent) { - for (listener in mainCanvas.keyListeners) { + for (listener in canvas.keyListeners) { listener.keyReleased(e) } } override fun keyTyped(e: KeyEvent) { - for (listener in mainCanvas.keyListeners) { + for (listener in canvas.keyListeners) { listener.keyTyped(e) } } @@ -287,27 +288,62 @@ class plugin : Plugin() { val originalY = adjustedY.toInt().coerceIn(0, gameImage!!.height - 1) val newEvent = MouseEvent( - mainCanvas, e.id, e.`when`, e.modifiersEx, + canvas, e.id, e.`when`, e.modifiersEx, originalX, originalY, e.clickCount, e.isPopupTrigger, e.button ) - mainCanvas.dispatchEvent(newEvent) + canvas.dispatchEvent(newEvent) } fun updateGameImage() { validateGameImage() + if (IsHD()) { + renderGlRaster() + } else { + renderSoftwareRaster() + } + repaint() + } + private fun renderGlRaster() { + val pixels = GlRenderer.pixelData // Assuming this holds the int[] BGRA pixel data from GlRenderer.readPixels() + val width = gameImage!!.width + val height = gameImage!!.height + + // Create a BufferedImage with the same dimensions as the gameImage + val bufferedImage = BufferedImage(width, height, BufferedImage.TYPE_INT_BGR) + + // Flip the image vertically by reversing the rows + val flippedPixels = IntArray(width * height) + for (y in 0 until height) { + // Calculate the source row (bottom to top) + val srcY = height - 1 - y + System.arraycopy(pixels, srcY * width, flippedPixels, y * width, width) + } + + // Set the flipped pixel data into the BufferedImage + bufferedImage.setRGB(0, 0, width, height, flippedPixels, 0, width) + + // Draw the BufferedImage onto the VolatileImage + val g = gameImage!!.createGraphics() + try { + g.drawImage(bufferedImage, 0, 0, null) + } finally { + g.dispose() + } + } + + private fun renderSoftwareRaster() { val g = gameImage!!.createGraphics() try { SoftwareRaster.frameBuffer.draw(g) } finally { g.dispose() } - repaint() } } - fun createAltCanvas(mainCanvas: Canvas): AltCanvas { - return AltCanvas(mainCanvas).apply { + fun createAltCanvas(): AltCanvas { + return AltCanvas().apply { preferredSize = Dimension(FIXED_WIDTH, 503) } } @@ -323,14 +359,12 @@ class plugin : Plugin() { val frame: Frame? = GameShell.frame if (frame != null) { // Create the AltCanvas and add it to the main frame - altCanvas = createAltCanvas(canvas) - canvas.isVisible = false + altCanvas = createAltCanvas() // Use BorderLayout for better layout control frame.layout = BorderLayout() // Add the AltCanvas in the center to ensure it scales properly with the window size altCanvas?.let { frame.add(it, BorderLayout.NORTH) } - frame.remove(canvas) } } @@ -415,6 +449,20 @@ class plugin : Plugin() { frame.layout = BorderLayout() frame.add(rightPanelWrapper, BorderLayout.EAST) + // Create a timer to delay execution by 2 seconds + Timer().schedule(object : TimerTask() { + override fun run() { + println("mode is: " + GetWindowMode().toString()) + if (GetWindowMode() != WindowMode.FIXED) { + // Perform any actions needed for non-fixed mode + } else { + //if (canvas.isShowing) { + // frame.remove(canvas) + // } + } + } + }, 2000) // 2000 milliseconds = 2 seconds + frame.revalidate() frame.repaint() pluginsReloaded = true @@ -490,7 +538,8 @@ class plugin : Plugin() { } override fun LateDraw(timeDelta: Long){ - // Update game image here + // Clear original canvas for scaled + if(!initialized) return altCanvas?.updateGameImage() } From 4f8bf464c5fff02379dfc2df77043c01332a314e Mon Sep 17 00:00:00 2001 From: downthecrop Date: Fri, 25 Oct 2024 21:22:16 -0700 Subject: [PATCH 27/47] HD Resize redraw --- client/src/main/java/rt4/GameShell.java | 6 +++-- client/src/main/java/rt4/GlRenderer.java | 2 +- .../src/main/kotlin/KondoKit/plugin.kt | 25 +++++++------------ 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/client/src/main/java/rt4/GameShell.java b/client/src/main/java/rt4/GameShell.java index 9bd0bd6..250f826 100644 --- a/client/src/main/java/rt4/GameShell.java +++ b/client/src/main/java/rt4/GameShell.java @@ -182,6 +182,7 @@ public abstract class GameShell extends Applet implements Runnable, FocusListene @OriginalMember(owner = "client!qh", name = "a", descriptor = "(Z)V") public static void method3662() { + System.out.println("Moving..."); @Pc(8) Container local8; if (fullScreenFrame != null) { local8 = fullScreenFrame; @@ -514,9 +515,10 @@ public abstract class GameShell extends Applet implements Runnable, FocusListene canvasScale = getCurrentDevice().getDefaultConfiguration().getDefaultTransform().getScaleX(); if (frame != null && fullScreenFrame == null) { @Pc(84) Insets insets = frame.getInsets(); - canvas.setLocation(insets.left + leftMargin, topMargin + insets.top); + // TODO: Add a flag to ignore this. + //canvas.setLocation(insets.left + leftMargin, topMargin + insets.top); } else { - canvas.setLocation(leftMargin, topMargin); + //canvas.setLocation(leftMargin, topMargin); } } this.mainRedraw(); diff --git a/client/src/main/java/rt4/GlRenderer.java b/client/src/main/java/rt4/GlRenderer.java index c7a7d2a..3ad7392 100644 --- a/client/src/main/java/rt4/GlRenderer.java +++ b/client/src/main/java/rt4/GlRenderer.java @@ -203,7 +203,7 @@ public final class GlRenderer { try { pixelData = readPixels(); drawable.swapBuffers(); - } catch (@Pc(3) Exception local3) {*, + } catch (@Pc(3) Exception local3) { } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 983576d..d9a3cfd 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -44,8 +44,6 @@ import java.awt.Font import java.awt.event.* import java.awt.image.BufferedImage import java.awt.image.VolatileImage -import java.util.* -import java.util.Timer import javax.swing.* @@ -449,20 +447,6 @@ class plugin : Plugin() { frame.layout = BorderLayout() frame.add(rightPanelWrapper, BorderLayout.EAST) - // Create a timer to delay execution by 2 seconds - Timer().schedule(object : TimerTask() { - override fun run() { - println("mode is: " + GetWindowMode().toString()) - if (GetWindowMode() != WindowMode.FIXED) { - // Perform any actions needed for non-fixed mode - } else { - //if (canvas.isShowing) { - // frame.remove(canvas) - // } - } - } - }, 2000) // 2000 milliseconds = 2 seconds - frame.revalidate() frame.repaint() pluginsReloaded = true @@ -540,6 +524,15 @@ class plugin : Plugin() { override fun LateDraw(timeDelta: Long){ // Clear original canvas for scaled if(!initialized) return + SwingUtilities.invokeLater { + if (GetWindowMode() == WindowMode.FIXED) { + if (canvas.isShowing) { + canvas.setLocation(-1000,-1000) + } + } else { + + } + } altCanvas?.updateGameImage() } From 15deb6216ff871349c4e2212f8bd1efcd91e4aa2 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Fri, 25 Oct 2024 21:26:43 -0700 Subject: [PATCH 28/47] skip unrequired movement --- plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index d9a3cfd..12d75cc 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -525,9 +525,11 @@ class plugin : Plugin() { // Clear original canvas for scaled if(!initialized) return SwingUtilities.invokeLater { + var p = Point(-1000,-1000) if (GetWindowMode() == WindowMode.FIXED) { - if (canvas.isShowing) { - canvas.setLocation(-1000,-1000) + if (canvas.location != p) { + println("Moving canvas offscreen"); + canvas.location = p; } } else { From 71afb2b385a563af892264ad8b96f60b7924729e Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sat, 26 Oct 2024 09:06:23 -0700 Subject: [PATCH 29/47] greatly reduce flickering --- client/src/main/java/rt4/DisplayMode.java | 6 - .../src/main/kotlin/KondoKit/HiscoresView.kt | 18 ++- .../main/kotlin/KondoKit/ScrollablePanel.kt | 76 ++++++------ .../src/main/kotlin/KondoKit/plugin.kt | 111 +++++++++++++----- 4 files changed, 131 insertions(+), 80 deletions(-) diff --git a/client/src/main/java/rt4/DisplayMode.java b/client/src/main/java/rt4/DisplayMode.java index 58bf779..440e79d 100644 --- a/client/src/main/java/rt4/DisplayMode.java +++ b/client/src/main/java/rt4/DisplayMode.java @@ -79,12 +79,6 @@ public final class DisplayMode { @OriginalMember(owner = "client!pm", name = "a", descriptor = "(ZIZIZII)V") public static void setWindowMode(@OriginalArg(0) boolean replaceCanvas, @OriginalArg(1) int newMode, @OriginalArg(2) boolean useHD, @OriginalArg(3) int currentMode, @OriginalArg(5) int width, @OriginalArg(6) int height) { - if(!GameShell.canvas.isShowing()){ - GameShell.frame.add(GameShell.canvas); - GameShell.canvas.revalidate(); - GameShell.frame.revalidate(); - GameShell.canvas.repaint(); - } if (useHD) { GlRenderer.quit(); } diff --git a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt index ecdeed0..f192098 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt @@ -7,9 +7,7 @@ import KondoKit.Helpers.formatHtmlLabelText import KondoKit.Helpers.getSpriteId import KondoKit.Helpers.showToast import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite -import KondoKit.plugin.Companion.POPUP_BACKGROUND import KondoKit.plugin.Companion.POPUP_FOREGROUND -import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR @@ -112,7 +110,9 @@ object HiscoresView { } else { text += e.keyChar } - repaint() + SwingUtilities.invokeLater { + repaint() + } } override fun keyPressed(e: KeyEvent) { if (e.isControlDown) { @@ -125,7 +125,9 @@ object HiscoresView { val clipboard = Toolkit.getDefaultToolkit().systemClipboard val pasteText = clipboard.getData(DataFlavor.stringFlavor) as String text += pasteText - repaint() + SwingUtilities.invokeLater { + repaint() + } } } } @@ -136,7 +138,9 @@ object HiscoresView { override fun mouseClicked(e: MouseEvent) { if (e.x > width - 20 && e.y < 20) { text = "" - repaint() + SwingUtilities.invokeLater { + repaint() + } } } }) @@ -144,7 +148,9 @@ object HiscoresView { Timer(500) { cursorVisible = !cursorVisible if(focusedView == VIEW_NAME) - repaint() + SwingUtilities.invokeLater { + repaint() + } }.start() } diff --git a/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt index 46f2b5a..c190c1a 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt @@ -9,6 +9,7 @@ import java.awt.Rectangle import java.awt.event.* import java.util.* import javax.swing.JPanel +import javax.swing.SwingUtilities class ScrollablePanel(private val content: JPanel) : JPanel() { private var lastMouseY = 0 @@ -80,20 +81,22 @@ class ScrollablePanel(private val content: JPanel) : JPanel() { } private fun handleResize() { - // Ensure the ScrollablePanel resizes with the frame - bounds = Rectangle(0, 0, 242, frame.height) + SwingUtilities.invokeLater{ + // Ensure the ScrollablePanel resizes with the frame + bounds = Rectangle(0, 0, 242, frame.height) - // Dynamically update content bounds and scrollbar on frame resize with buffer - content.bounds = Rectangle(0, 0, 242, content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer)) - showScrollbar = content.height > frame.height + // Dynamically update content bounds and scrollbar on frame resize with buffer + content.bounds = Rectangle(0, 0, 242, content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer)) + showScrollbar = content.height > frame.height - currentOffsetY = 0 + currentOffsetY = 0 - content.setLocation(0, currentOffsetY) - updateScrollbar() + content.setLocation(0, currentOffsetY) + updateScrollbar() - revalidate() - repaint() + revalidate() + repaint() + } } private fun scrollContent(deltaY: Int) { @@ -102,40 +105,41 @@ class ScrollablePanel(private val content: JPanel) : JPanel() { content.setLocation(0, currentOffsetY) return } + SwingUtilities.invokeLater { + currentOffsetY += deltaY - currentOffsetY += deltaY + // Apply buffer to maxOffset + val maxOffset = (frame.height - content.height + viewBuffer).coerceAtMost(0) + currentOffsetY = currentOffsetY.coerceAtMost(0).coerceAtLeast(maxOffset) - // Apply buffer to maxOffset - val maxOffset = (frame.height - content.height + viewBuffer).coerceAtMost(0) - currentOffsetY = currentOffsetY.coerceAtMost(0).coerceAtLeast(maxOffset) + content.setLocation(0, currentOffsetY) - content.setLocation(0, currentOffsetY) - - val contentHeight = content.height - val viewHeight = frame.height + viewBuffer - val scrollableRatio = viewHeight.toDouble() / contentHeight - scrollbarY = ((-currentOffsetY / contentHeight.toDouble()) * viewHeight).toInt() - scrollbarHeight = (viewHeight * scrollableRatio).toInt().coerceAtLeast(20) - - repaint() - } - - private fun updateScrollbar() { - showScrollbar = content.height > frame.height - - val contentHeight = content.height - val viewHeight = frame.height + viewBuffer - - if (showScrollbar) { + val contentHeight = content.height + val viewHeight = frame.height + viewBuffer val scrollableRatio = viewHeight.toDouble() / contentHeight scrollbarY = ((-currentOffsetY / contentHeight.toDouble()) * viewHeight).toInt() scrollbarHeight = (viewHeight * scrollableRatio).toInt().coerceAtLeast(20) - } else { - scrollbarY = 0 - scrollbarHeight = 0 + repaint() } + } - repaint() + private fun updateScrollbar() { + SwingUtilities.invokeLater { + showScrollbar = content.height > frame.height + + val contentHeight = content.height + val viewHeight = frame.height + viewBuffer + + if (showScrollbar) { + val scrollableRatio = viewHeight.toDouble() / contentHeight + scrollbarY = ((-currentOffsetY / contentHeight.toDouble()) * viewHeight).toInt() + scrollbarHeight = (viewHeight * scrollableRatio).toInt().coerceAtLeast(20) + } else { + scrollbarY = 0 + scrollbarHeight = 0 + } + repaint() + } } override fun paintComponent(g: Graphics) { diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 12d75cc..fe6f249 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -147,7 +147,8 @@ class plugin : Plugin() { } lastLogin = Player.usernameInput.toString() } - class AltCanvas() : JPanel() { + + class AltCanvas : Canvas() { private var gameImage: VolatileImage? = null private var scaleX = 1.0 private var scaleY = 1.0 @@ -207,15 +208,19 @@ class plugin : Plugin() { requestFocusInWindow() } + override fun update(g: Graphics) { + paint(g) + } + private fun validateGameImage() { val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration if (gameImage == null) { - gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.TRANSLUCENT) + gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE) renderGameImage() } else { val status = gameImage!!.validate(gc) if (status == VolatileImage.IMAGE_INCOMPATIBLE) { - gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.TRANSLUCENT) + gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE) renderGameImage() } else if (status == VolatileImage.IMAGE_RESTORED) { renderGameImage() @@ -237,20 +242,35 @@ class plugin : Plugin() { } } - override fun paintComponent(g: Graphics) { - super.paintComponent(g) + override fun paint(g: Graphics) { val g2d = g as Graphics2D - - // Set the desired background fill color here g2d.color = Color.BLACK g2d.fillRect(0, 0, width, height) - validateGameImage() + // Validate image within paint to ensure compatibility with GraphicsConfiguration + var valid = false + do { + val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration + if (gameImage == null) { + gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE) + renderGameImage() + } else { + val status = gameImage!!.validate(gc) + when (status) { + VolatileImage.IMAGE_INCOMPATIBLE -> { + gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE) + renderGameImage() + } + VolatileImage.IMAGE_RESTORED -> renderGameImage() + VolatileImage.IMAGE_OK -> valid = true + } + } + } while (!valid) + // Continue with rendering the image gameImage?.let { image -> g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) - - // Calculate aspect-ratio-preserving scale + // Scaling and centering val imageAspect = image.width.toDouble() / image.height.toDouble() val panelAspect = width.toDouble() / height.toDouble() @@ -289,7 +309,6 @@ class plugin : Plugin() { canvas, e.id, e.`when`, e.modifiersEx, originalX, originalY, e.clickCount, e.isPopupTrigger, e.button ) - canvas.dispatchEvent(newEvent) } @@ -383,8 +402,11 @@ class plugin : Plugin() { } } rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) + rightPanelWrapper?.let { it.isDoubleBuffered = true } rightPanelWrapper?.revalidate() - rightPanelWrapper?.repaint() + SwingUtilities.invokeLater { + rightPanelWrapper?.repaint() + } } fun OnKondoValueUpdated(){ @@ -446,9 +468,7 @@ class plugin : Plugin() { frame.remove(rightPanelWrapper) frame.layout = BorderLayout() frame.add(rightPanelWrapper, BorderLayout.EAST) - frame.revalidate() - frame.repaint() pluginsReloaded = true reloadInterfaces = true return true @@ -476,7 +496,9 @@ class plugin : Plugin() { xpTrackerView?.revalidate() if(focusedView == XPTrackerView.VIEW_NAME) - xpTrackerView?.repaint() + SwingUtilities.invokeLater { + xpTrackerView?.repaint() + } updateWidget(xpWidget, xp) } @@ -522,22 +544,35 @@ class plugin : Plugin() { } override fun LateDraw(timeDelta: Long){ - // Clear original canvas for scaled if(!initialized) return SwingUtilities.invokeLater { - var p = Point(-1000,-1000) if (GetWindowMode() == WindowMode.FIXED) { - if (canvas.location != p) { - println("Moving canvas offscreen"); - canvas.location = p; + if (canvas.parent !== hiddenFrame?.contentPane) { + println("Moving canvas to hidden frame") + initializeHiddenFrame() + frame.remove(canvas) // Remove from main frame if necessary + hiddenFrame?.contentPane?.add(canvas) + hiddenFrame?.pack() } - } else { - } } - altCanvas?.updateGameImage() + altCanvas?.updateGameImage() // Update the game image as needed } + private var hiddenFrame: JFrame? = null + + fun initializeHiddenFrame() { + if (hiddenFrame == null) { + hiddenFrame = JFrame().apply { + isUndecorated = true + isVisible = false // Keep it hidden + setSize(1, 1) // Minimal size + defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE + } + } + } + + private fun initKondoUI(){ DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) if(!allSpritesLoaded()) return; @@ -683,7 +718,9 @@ class plugin : Plugin() { val formattedXpPerHour = formatNumber(xpPerHour) xpWidget.xpPerHourLabel.text = formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) - xpWidget.container.repaint() + SwingUtilities.invokeLater{ + xpWidget.container.repaint() + } } totalXP?.let { totalXPWidget -> @@ -692,7 +729,9 @@ class plugin : Plugin() { val formattedTotalXpPerHour = formatNumber(totalXPPerHour) totalXPWidget.xpPerHourLabel.text = formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) - totalXPWidget.container.repaint() + SwingUtilities.invokeLater{ + totalXPWidget.container.repaint() + } } } @@ -717,11 +756,14 @@ class plugin : Plugin() { // Revalidate and repaint necessary panels mainContentPanel.revalidate() - mainContentPanel.repaint() rightPanelWrapper?.revalidate() - rightPanelWrapper?.repaint() frame?.revalidate() - frame?.repaint() + + SwingUtilities.invokeLater{ + mainContentPanel.repaint() + rightPanelWrapper?.repaint() + frame?.repaint() + } focusedView = viewName } @@ -784,15 +826,20 @@ class plugin : Plugin() { override fun mouseEntered(e: MouseEvent?) { background = WIDGET_COLOR.darker() imageCanvas.fillColor = WIDGET_COLOR.darker() - imageCanvas.repaint() - repaint() + SwingUtilities.invokeLater{ + imageCanvas.repaint() + repaint() + } } override fun mouseExited(e: MouseEvent?) { background = WIDGET_COLOR imageCanvas.fillColor = WIDGET_COLOR - imageCanvas.repaint() - repaint() + SwingUtilities.invokeLater{ + imageCanvas.repaint() + repaint() + } + } override fun mouseClicked(e: MouseEvent?) { From 83fe4805acd2e70ef27abd958b29640bb4787ed4 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sat, 26 Oct 2024 09:59:25 -0700 Subject: [PATCH 30/47] GC issues + some late invokes --- client/src/main/java/rt4/GlRenderer.java | 35 ++++- .../src/main/kotlin/KondoKit/plugin.kt | 144 +++++++++--------- 2 files changed, 99 insertions(+), 80 deletions(-) diff --git a/client/src/main/java/rt4/GlRenderer.java b/client/src/main/java/rt4/GlRenderer.java index 3ad7392..3f564b3 100644 --- a/client/src/main/java/rt4/GlRenderer.java +++ b/client/src/main/java/rt4/GlRenderer.java @@ -9,6 +9,7 @@ import org.openrs2.deob.annotation.OriginalMember; import org.openrs2.deob.annotation.Pc; import java.awt.*; +import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.nio.charset.StandardCharsets; @@ -24,7 +25,10 @@ public final class GlRenderer { public static float hFOV = 0; - public static int[] pixelData = null; + + private static ByteBuffer pixelByteBuffer; + private static IntBuffer pixelIntBuffer; + public static int[] pixelData; @OriginalMember(owner = "client!tf", name = "c", descriptor = "F") private static float aFloat30; @@ -201,18 +205,33 @@ public final class GlRenderer { @OriginalMember(owner = "client!tf", name = "d", descriptor = "()V") public static void swapBuffers() { try { - pixelData = readPixels(); + readPixels(); drawable.swapBuffers(); } catch (@Pc(3) Exception local3) { } } - @OriginalMember(owner = "client!tf", name = "readPixels", descriptor = "()int[]") - public static int[] readPixels() { - int[] pixels = new int[canvasWidth * canvasHeight]; - IntBuffer buffer = IntBuffer.wrap(pixels); - gl.glReadPixels(0, 0, canvasWidth, canvasHeight, GL2.GL_BGRA, GlRenderer.bigEndian ? GL2.GL_UNSIGNED_INT_8_8_8_8_REV : GL2.GL_UNSIGNED_BYTE, buffer); - return pixels; + public static void initializePixelBuffer(int width, int height) { + // Allocate ByteBuffer for BGRA pixels (4 bytes per pixel) + pixelByteBuffer = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder()); + pixelIntBuffer = pixelByteBuffer.asIntBuffer(); + pixelData = new int[width * height]; + } + + public static void readPixels() { + // Ensure the pixel buffer is initialized with the correct size + if (pixelByteBuffer == null || pixelIntBuffer.capacity() != canvasWidth * canvasHeight) { + initializePixelBuffer(canvasWidth, canvasHeight); + } + + // Read pixels into the direct ByteBuffer + gl.glReadPixels(0, 0, canvasWidth, canvasHeight, GL2.GL_BGRA, + GlRenderer.bigEndian ? GL2.GL_UNSIGNED_INT_8_8_8_8_REV : GL2.GL_UNSIGNED_BYTE, + pixelByteBuffer); + + // Convert to int array if needed + pixelIntBuffer.rewind(); // Prepare the IntBuffer for reading + pixelIntBuffer.get(pixelData, 0, pixelData.length); // Transfer to pixelData array if necessary } @OriginalMember(owner = "client!tf", name = "a", descriptor = "(Z)V") diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index fe6f249..ea53905 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -150,6 +150,8 @@ class plugin : Plugin() { class AltCanvas : Canvas() { private var gameImage: VolatileImage? = null + private var flippedPixels: IntArray? = null + private var bufferImage: BufferedImage? = null private var scaleX = 1.0 private var scaleY = 1.0 private var offsetX = 0 @@ -158,6 +160,8 @@ class plugin : Plugin() { init { validateGameImage() + isFocusable = true + requestFocusInWindow() addMouseListener(object : MouseAdapter() { override fun mousePressed(e: MouseEvent) { @@ -212,6 +216,11 @@ class plugin : Plugin() { paint(g) } + override fun addNotify() { + super.addNotify() + //createBufferStrategy(2) // Double buffering for V-Sync, called only after the peer is created + } + private fun validateGameImage() { val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration if (gameImage == null) { @@ -294,6 +303,9 @@ class plugin : Plugin() { val x = offsetX val y = offsetY g2d.drawImage(image, x, y, drawWidth, drawHeight, null) + g2d.dispose() + //bufferStrategy.show() // Shows the buffer with V-Sync enabled + Toolkit.getDefaultToolkit().sync() // Ensures V-Sync on some systems } } @@ -322,30 +334,27 @@ class plugin : Plugin() { repaint() } private fun renderGlRaster() { - val pixels = GlRenderer.pixelData // Assuming this holds the int[] BGRA pixel data from GlRenderer.readPixels() - val width = gameImage!!.width - val height = gameImage!!.height - - // Create a BufferedImage with the same dimensions as the gameImage - val bufferedImage = BufferedImage(width, height, BufferedImage.TYPE_INT_BGR) - - // Flip the image vertically by reversing the rows - val flippedPixels = IntArray(width * height) - for (y in 0 until height) { - // Calculate the source row (bottom to top) - val srcY = height - 1 - y - System.arraycopy(pixels, srcY * width, flippedPixels, y * width, width) + if (flippedPixels == null || flippedPixels!!.size != gameImage!!.width * gameImage!!.height) { + flippedPixels = IntArray(gameImage!!.width * gameImage!!.height) } - // Set the flipped pixel data into the BufferedImage - bufferedImage.setRGB(0, 0, width, height, flippedPixels, 0, width) + // Initialize bufferImage only once and reuse it + if (bufferImage == null || bufferImage!!.width != gameImage!!.width || bufferImage!!.height != gameImage!!.height) { + bufferImage = BufferedImage(gameImage!!.width, gameImage!!.height, BufferedImage.TYPE_INT_BGR) + } - // Draw the BufferedImage onto the VolatileImage - val g = gameImage!!.createGraphics() - try { - g.drawImage(bufferedImage, 0, 0, null) - } finally { - g.dispose() + val width = gameImage!!.width + val height = gameImage!!.height + val pixels = GlRenderer.pixelData // Retrieve BGRA pixel data + for (y in 0 until height) { + System.arraycopy(pixels, (height - 1 - y) * width, flippedPixels, y * width, width) + } + + bufferImage!!.setRGB(0, 0, width, height, flippedPixels, 0, width) + + gameImage?.createGraphics()?.apply { + drawImage(bufferImage, 0, 0, null) + dispose() } } @@ -404,9 +413,7 @@ class plugin : Plugin() { rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) rightPanelWrapper?.let { it.isDoubleBuffered = true } rightPanelWrapper?.revalidate() - SwingUtilities.invokeLater { - rightPanelWrapper?.repaint() - } + rightPanelWrapper?.repaint() } fun OnKondoValueUpdated(){ @@ -462,9 +469,7 @@ class plugin : Plugin() { override fun OnPluginsReloaded(): Boolean { if (!initialized) return true - UpdateDisplaySettings() - frame.remove(rightPanelWrapper) frame.layout = BorderLayout() frame.add(rightPanelWrapper, BorderLayout.EAST) @@ -475,32 +480,31 @@ class plugin : Plugin() { } override fun OnXPUpdate(skillId: Int, xp: Int) { - if (!initialXP.containsKey(skillId)) { - initialXP[skillId] = xp - return - } + SwingUtilities.invokeLater{ + if (!initialXP.containsKey(skillId)) { + initialXP[skillId] = xp + return@invokeLater + } + var xpWidget = xpWidgets[skillId] + if (xpWidget != null) { + updateWidget(xpWidget, xp) + } else { + val previousXp = initialXP[skillId] ?: xp + if (xp == initialXP[skillId]) return@invokeLater - var xpWidget = xpWidgets[skillId] + xpWidget = createXPWidget(skillId, previousXp) + xpWidgets[skillId] = xpWidget - if (xpWidget != null) { - updateWidget(xpWidget, xp) - } else { - val previousXp = initialXP[skillId] ?: xp - if (xp == initialXP[skillId]) return + xpTrackerView?.add(wrappedWidget(xpWidget.container)) + xpTrackerView?.add(Box.createVerticalStrut(5)) - xpWidget = createXPWidget(skillId, previousXp) - xpWidgets[skillId] = xpWidget - - xpTrackerView?.add(wrappedWidget(xpWidget.container)) - xpTrackerView?.add(Box.createVerticalStrut(5)) - - xpTrackerView?.revalidate() - if(focusedView == XPTrackerView.VIEW_NAME) - SwingUtilities.invokeLater { + if(focusedView == XPTrackerView.VIEW_NAME) { + xpTrackerView?.revalidate() xpTrackerView?.repaint() } - updateWidget(xpWidget, xp) + updateWidget(xpWidget, xp) + } } } @@ -545,16 +549,19 @@ class plugin : Plugin() { override fun LateDraw(timeDelta: Long){ if(!initialized) return - SwingUtilities.invokeLater { - if (GetWindowMode() == WindowMode.FIXED) { - if (canvas.parent !== hiddenFrame?.contentPane) { - println("Moving canvas to hidden frame") - initializeHiddenFrame() - frame.remove(canvas) // Remove from main frame if necessary - hiddenFrame?.contentPane?.add(canvas) - hiddenFrame?.pack() + if (GetWindowMode() == WindowMode.FIXED) { + if (canvas.parent !== hiddenFrame?.contentPane) { + if(altCanvas?.parent != frame) { + frame.add(altCanvas) } + println("Moving canvas to hidden frame") + initializeHiddenFrame() + frame.remove(canvas) // Remove from main frame if necessary + hiddenFrame?.contentPane?.add(canvas) + hiddenFrame?.pack() } + } else { + frame.remove(altCanvas) } altCanvas?.updateGameImage() // Update the game image as needed } @@ -716,9 +723,9 @@ class plugin : Plugin() { val elapsedTime = (System.currentTimeMillis() - xpWidget.startTime) / 1000.0 / 60.0 / 60.0 val xpPerHour = if (elapsedTime > 0) (xpWidget.totalXpGained / elapsedTime).toInt() else 0 val formattedXpPerHour = formatNumber(xpPerHour) - xpWidget.xpPerHourLabel.text = - formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) SwingUtilities.invokeLater{ + xpWidget.xpPerHourLabel.text = + formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) xpWidget.container.repaint() } } @@ -727,9 +734,9 @@ class plugin : Plugin() { val elapsedTime = (System.currentTimeMillis() - totalXPWidget.startTime) / 1000.0 / 60.0 / 60.0 val totalXPPerHour = if (elapsedTime > 0) (totalXPWidget.totalXpGained / elapsedTime).toInt() else 0 val formattedTotalXpPerHour = formatNumber(totalXPPerHour) - totalXPWidget.xpPerHourLabel.text = - formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) SwingUtilities.invokeLater{ + totalXPWidget.xpPerHourLabel.text = + formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) totalXPWidget.container.repaint() } } @@ -759,11 +766,9 @@ class plugin : Plugin() { rightPanelWrapper?.revalidate() frame?.revalidate() - SwingUtilities.invokeLater{ - mainContentPanel.repaint() - rightPanelWrapper?.repaint() - frame?.repaint() - } + mainContentPanel.repaint() + rightPanelWrapper?.repaint() + frame?.repaint() focusedView = viewName } @@ -826,20 +831,15 @@ class plugin : Plugin() { override fun mouseEntered(e: MouseEvent?) { background = WIDGET_COLOR.darker() imageCanvas.fillColor = WIDGET_COLOR.darker() - SwingUtilities.invokeLater{ - imageCanvas.repaint() - repaint() - } + imageCanvas.repaint() + repaint() } override fun mouseExited(e: MouseEvent?) { background = WIDGET_COLOR imageCanvas.fillColor = WIDGET_COLOR - SwingUtilities.invokeLater{ - imageCanvas.repaint() - repaint() - } - + imageCanvas.repaint() + repaint() } override fun mouseClicked(e: MouseEvent?) { From e7f46f1006ab0e8c4c65da928e46021a2589e108 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sat, 26 Oct 2024 22:31:43 -0700 Subject: [PATCH 31/47] Constant for FIXED_HEIGHT + transfercomponent helper --- .../src/main/kotlin/KondoKit/plugin.kt | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index ea53905..9fe4ef7 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -40,6 +40,7 @@ import rt4.GameShell.frame import rt4.client.js5Archive8 import rt4.client.mainLoadState import java.awt.* +import java.awt.Component import java.awt.Font import java.awt.event.* import java.awt.image.BufferedImage @@ -91,6 +92,7 @@ class plugin : Plugin() { var uiOffset = 0 private const val FIXED_WIDTH = 765 + private const val FIXED_HEIGHT = 503 private const val NAVBAR_WIDTH = 30 private const val MAIN_CONTENT_WIDTH = 242 private const val WRENCH_ICON = 907 @@ -111,6 +113,7 @@ class plugin : Plugin() { private var lastUIOffset = 0 private const val HIDDEN_VIEW = "HIDDEN" private val drawActions = mutableListOf<() -> Unit>() + private var hiddenFrame: JFrame? = null fun registerDrawAction(action: () -> Unit) { synchronized(drawActions) { @@ -224,12 +227,12 @@ class plugin : Plugin() { private fun validateGameImage() { val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration if (gameImage == null) { - gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE) + gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) renderGameImage() } else { val status = gameImage!!.validate(gc) if (status == VolatileImage.IMAGE_INCOMPATIBLE) { - gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE) + gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) renderGameImage() } else if (status == VolatileImage.IMAGE_RESTORED) { renderGameImage() @@ -261,13 +264,13 @@ class plugin : Plugin() { do { val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration if (gameImage == null) { - gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE) + gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) renderGameImage() } else { val status = gameImage!!.validate(gc) when (status) { VolatileImage.IMAGE_INCOMPATIBLE -> { - gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE) + gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) renderGameImage() } VolatileImage.IMAGE_RESTORED -> renderGameImage() @@ -370,7 +373,7 @@ class plugin : Plugin() { fun createAltCanvas(): AltCanvas { return AltCanvas().apply { - preferredSize = Dimension(FIXED_WIDTH, 503) + preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) } } @@ -547,39 +550,51 @@ class plugin : Plugin() { } } - override fun LateDraw(timeDelta: Long){ - if(!initialized) return + override fun LateDraw(timeDelta: Long) { + if (!initialized) return if (GetWindowMode() == WindowMode.FIXED) { - if (canvas.parent !== hiddenFrame?.contentPane) { - if(altCanvas?.parent != frame) { + if (canvas.parent != hiddenFrame?.contentPane) { + if (altCanvas?.parent != frame) { frame.add(altCanvas) } - println("Moving canvas to hidden frame") initializeHiddenFrame() - frame.remove(canvas) // Remove from main frame if necessary - hiddenFrame?.contentPane?.add(canvas) - hiddenFrame?.pack() + hiddenFrame?.let { transferComponent(canvas, frame, it) } } } else { - frame.remove(altCanvas) + if (altCanvas?.parent == frame) { + frame.remove(altCanvas) + } } altCanvas?.updateGameImage() // Update the game image as needed } - private var hiddenFrame: JFrame? = null - fun initializeHiddenFrame() { + fun transferComponent(component: Component, fromFrame: Frame, toFrame: Frame) { + println("Transferring component") + fromFrame.remove(component) + toFrame.add(component) + toFrame.pack() + fromFrame.revalidate() + toFrame.revalidate() + fromFrame.repaint() + toFrame.repaint() + } + + fun initializeHiddenFrame(debugMode: Boolean = true) { if (hiddenFrame == null) { hiddenFrame = JFrame().apply { - isUndecorated = true - isVisible = false // Keep it hidden - setSize(1, 1) // Minimal size + isUndecorated = !debugMode + isFocusable = false + isVisible = debugMode // Show frame if debugMode is true + setSize( + if(debugMode) FIXED_WIDTH else 1, + if(debugMode) FIXED_HEIGHT else 1 + ) defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE } } } - private fun initKondoUI(){ DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) if(!allSpritesLoaded()) return; From 8180e202814794f346d1437d328b86e9042dbbaa Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sat, 26 Oct 2024 22:33:54 -0700 Subject: [PATCH 32/47] Removing debug from client + add print for unparented altcanvas --- client/src/main/java/rt4/GameShell.java | 1 - plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/main/java/rt4/GameShell.java b/client/src/main/java/rt4/GameShell.java index 250f826..68e6c32 100644 --- a/client/src/main/java/rt4/GameShell.java +++ b/client/src/main/java/rt4/GameShell.java @@ -182,7 +182,6 @@ public abstract class GameShell extends Applet implements Runnable, FocusListene @OriginalMember(owner = "client!qh", name = "a", descriptor = "(Z)V") public static void method3662() { - System.out.println("Moving..."); @Pc(8) Container local8; if (fullScreenFrame != null) { local8 = fullScreenFrame; diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 9fe4ef7..cd2b50a 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -328,6 +328,9 @@ class plugin : Plugin() { } fun updateGameImage() { + if(this.parent == null) { + println("Unparented.. skipping update.") + } validateGameImage() if (IsHD()) { renderGlRaster() From 1f1718d9179ec44cf82aef13571ffeccfecceae1 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 27 Oct 2024 08:10:38 -0700 Subject: [PATCH 33/47] Keep the canvas in the frame but change the Z order --- .../main/java/plugin/PluginRepository.java | 6 +- client/src/main/java/rt4/GlRenderer.java | 2 +- .../src/main/kotlin/KondoKit/plugin.kt | 65 +++++-------------- 3 files changed, 20 insertions(+), 53 deletions(-) diff --git a/client/src/main/java/plugin/PluginRepository.java b/client/src/main/java/plugin/PluginRepository.java index 55faf80..4225c8c 100644 --- a/client/src/main/java/plugin/PluginRepository.java +++ b/client/src/main/java/plugin/PluginRepository.java @@ -70,7 +70,7 @@ public class PluginRepository { File pluginsDirectory = new File(GlobalJsonConfig.instance.pluginsFolder); if (!pluginsDirectory.exists()) { - System.out.println("Skipping plugin initialization - " + pluginsDirectory.getAbsolutePath() + " does not exist."); + //System.out.println("Skipping plugin initialization - " + pluginsDirectory.getAbsolutePath() + " does not exist."); return; } @@ -120,7 +120,7 @@ public class PluginRepository { } if (loadedPlugins.containsKey(info)) { - System.out.println("Skipping reloading of plugin " + file.getName() + " as it already exists and has OnPluginsReloaded."); + //System.out.println("Skipping reloading of plugin " + file.getName() + " as it already exists and has OnPluginsReloaded."); continue; } @@ -143,7 +143,7 @@ public class PluginRepository { loader.loadClass(file.getName() + "." + f.getName().replace(".class","")); } - System.out.println("Successfully loaded plugin " + file.getName() + ", version " + info.version); + //System.out.println("Successfully loaded plugin " + file.getName() + ", version " + info.version); } } catch (Exception e) { System.err.println("Unexpected exception during plugin initialization:"); diff --git a/client/src/main/java/rt4/GlRenderer.java b/client/src/main/java/rt4/GlRenderer.java index 3f564b3..d644740 100644 --- a/client/src/main/java/rt4/GlRenderer.java +++ b/client/src/main/java/rt4/GlRenderer.java @@ -205,8 +205,8 @@ public final class GlRenderer { @OriginalMember(owner = "client!tf", name = "d", descriptor = "()V") public static void swapBuffers() { try { - readPixels(); drawable.swapBuffers(); + readPixels(); } catch (@Pc(3) Exception local3) { } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index cd2b50a..2635755 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -40,7 +40,6 @@ import rt4.GameShell.frame import rt4.client.js5Archive8 import rt4.client.mainLoadState import java.awt.* -import java.awt.Component import java.awt.Font import java.awt.event.* import java.awt.image.BufferedImage @@ -113,7 +112,6 @@ class plugin : Plugin() { private var lastUIOffset = 0 private const val HIDDEN_VIEW = "HIDDEN" private val drawActions = mutableListOf<() -> Unit>() - private var hiddenFrame: JFrame? = null fun registerDrawAction(action: () -> Unit) { synchronized(drawActions) { @@ -390,13 +388,13 @@ class plugin : Plugin() { System.setProperty("swing.aatext", "false") val frame: Frame? = GameShell.frame if (frame != null) { + frame.layout = BorderLayout() // Create the AltCanvas and add it to the main frame altCanvas = createAltCanvas() + altCanvas?.let { frame.add(it) } // Use BorderLayout for better layout control - frame.layout = BorderLayout() - - // Add the AltCanvas in the center to ensure it scales properly with the window size - altCanvas?.let { frame.add(it, BorderLayout.NORTH) } + frame.setComponentZOrder(altCanvas, 0) + frame.setComponentZOrder(canvas, 1) } } @@ -409,6 +407,7 @@ class plugin : Plugin() { if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + uiOffset) { frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + uiOffset, frame.height) } + canvas.setLocation(0,0) val difference = frame.width - (uiOffset + currentScrollPaneWidth) altCanvas?.size = Dimension(difference, frame.height - 30) } @@ -486,17 +485,16 @@ class plugin : Plugin() { } override fun OnXPUpdate(skillId: Int, xp: Int) { - SwingUtilities.invokeLater{ if (!initialXP.containsKey(skillId)) { initialXP[skillId] = xp - return@invokeLater + return } var xpWidget = xpWidgets[skillId] if (xpWidget != null) { updateWidget(xpWidget, xp) } else { val previousXp = initialXP[skillId] ?: xp - if (xp == initialXP[skillId]) return@invokeLater + if (xp == initialXP[skillId]) return xpWidget = createXPWidget(skillId, previousXp) xpWidgets[skillId] = xpWidget @@ -511,7 +509,6 @@ class plugin : Plugin() { updateWidget(xpWidget, xp) } - } } override fun Draw(timeDelta: Long) { @@ -555,49 +552,16 @@ class plugin : Plugin() { override fun LateDraw(timeDelta: Long) { if (!initialized) return - if (GetWindowMode() == WindowMode.FIXED) { - if (canvas.parent != hiddenFrame?.contentPane) { - if (altCanvas?.parent != frame) { - frame.add(altCanvas) - } - initializeHiddenFrame() - hiddenFrame?.let { transferComponent(canvas, frame, it) } - } + if(GetWindowMode() == WindowMode.RESIZABLE){ + frame.setComponentZOrder(altCanvas, 1) + frame.setComponentZOrder(canvas, 0) } else { - if (altCanvas?.parent == frame) { - frame.remove(altCanvas) - } + frame.setComponentZOrder(altCanvas, 0) + frame.setComponentZOrder(canvas, 1) } altCanvas?.updateGameImage() // Update the game image as needed } - - fun transferComponent(component: Component, fromFrame: Frame, toFrame: Frame) { - println("Transferring component") - fromFrame.remove(component) - toFrame.add(component) - toFrame.pack() - fromFrame.revalidate() - toFrame.revalidate() - fromFrame.repaint() - toFrame.repaint() - } - - fun initializeHiddenFrame(debugMode: Boolean = true) { - if (hiddenFrame == null) { - hiddenFrame = JFrame().apply { - isUndecorated = !debugMode - isFocusable = false - isVisible = debugMode // Show frame if debugMode is true - setSize( - if(debugMode) FIXED_WIDTH else 1, - if(debugMode) FIXED_HEIGHT else 1 - ) - defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE - } - } - } - private fun initKondoUI(){ DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) if(!allSpritesLoaded()) return; @@ -720,7 +684,10 @@ class plugin : Plugin() { } frame.layout = BorderLayout() - rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) } + rightPanelWrapper?.let { + frame.add(it, BorderLayout.EAST) + frame.setComponentZOrder(it, 2) + } if(!launchMinimized){ setActiveView(XPTrackerView.VIEW_NAME) From 341d6758c152719ee4c15115c5cf35a5ebcfbfef Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 27 Oct 2024 19:40:24 -0700 Subject: [PATCH 34/47] Simplify altcanvas --- .../src/main/kotlin/KondoKit/plugin.kt | 238 ++++++------------ 1 file changed, 77 insertions(+), 161 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 2635755..a16e748 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -35,6 +35,7 @@ import plugin.api.* import plugin.api.API.* import plugin.api.FontColor.fromColor import rt4.* +import rt4.DisplayMode import rt4.GameShell.canvas import rt4.GameShell.frame import rt4.client.js5Archive8 @@ -111,6 +112,7 @@ class plugin : Plugin() { private var lastClickTime = 0L private var lastUIOffset = 0 private const val HIDDEN_VIEW = "HIDDEN" + private var altCanvas: AltCanvas? = null private val drawActions = mutableListOf<() -> Unit>() fun registerDrawAction(action: () -> Unit) { @@ -151,104 +153,64 @@ class plugin : Plugin() { class AltCanvas : Canvas() { private var gameImage: VolatileImage? = null - private var flippedPixels: IntArray? = null - private var bufferImage: BufferedImage? = null + private var flippedPixels = IntArray(FIXED_WIDTH * FIXED_HEIGHT) + private var bufferImage = BufferedImage(FIXED_WIDTH, FIXED_HEIGHT, BufferedImage.TYPE_INT_BGR) private var scaleX = 1.0 private var scaleY = 1.0 private var offsetX = 0 private var offsetY = 0 - init { - validateGameImage() isFocusable = true requestFocusInWindow() addMouseListener(object : MouseAdapter() { - override fun mousePressed(e: MouseEvent) { - relayMouseEvent(e) - } - - override fun mouseReleased(e: MouseEvent) { - relayMouseEvent(e) - } - - override fun mouseClicked(e: MouseEvent) { - relayMouseEvent(e) - } + override fun mousePressed(e: MouseEvent) = relayMouseEvent(e) + override fun mouseReleased(e: MouseEvent) = relayMouseEvent(e) + override fun mouseClicked(e: MouseEvent) = relayMouseEvent(e) }) addMouseMotionListener(object : MouseMotionAdapter() { - override fun mouseMoved(e: MouseEvent) { - relayMouseEvent(e) - } - - override fun mouseDragged(e: MouseEvent) { - relayMouseEvent(e) - } + override fun mouseMoved(e: MouseEvent) = relayMouseEvent(e) + override fun mouseDragged(e: MouseEvent) = relayMouseEvent(e) }) - // Register a KeyAdapter for handling key events addKeyListener(object : KeyAdapter() { - override fun keyPressed(e: KeyEvent) { - for (listener in canvas.keyListeners) { - listener.keyPressed(e) - } - } - - override fun keyReleased(e: KeyEvent) { - for (listener in canvas.keyListeners) { - listener.keyReleased(e) - } - } - - override fun keyTyped(e: KeyEvent) { - for (listener in canvas.keyListeners) { - listener.keyTyped(e) - } - } + override fun keyPressed(e: KeyEvent) = relayKeyEvent(e) { it.keyPressed(e) } + override fun keyReleased(e: KeyEvent) = relayKeyEvent(e) { it.keyReleased(e) } + override fun keyTyped(e: KeyEvent) = relayKeyEvent(e) { it.keyTyped(e) } }) - - isFocusable = true - requestFocusInWindow() } - override fun update(g: Graphics) { - paint(g) - } + override fun update(g: Graphics) = paint(g) override fun addNotify() { super.addNotify() - //createBufferStrategy(2) // Double buffering for V-Sync, called only after the peer is created + validateGameImage() } private fun validateGameImage() { val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration - if (gameImage == null) { - gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) - renderGameImage() - } else { - val status = gameImage!!.validate(gc) - if (status == VolatileImage.IMAGE_INCOMPATIBLE) { - gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) - renderGameImage() - } else if (status == VolatileImage.IMAGE_RESTORED) { - renderGameImage() + gameImage?.let { + when (it.validate(gc)) { + VolatileImage.IMAGE_INCOMPATIBLE -> createGameImage(gc) + VolatileImage.IMAGE_RESTORED -> renderGameImage() } - } + } ?: createGameImage(gc) + } + + private fun createGameImage(gc: GraphicsConfiguration) { + gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) + renderGameImage() } private fun renderGameImage() { - val g = gameImage!!.createGraphics() - try { - // Initial drawing code - g.color = Color.RED - g.fillRect(0, 0, gameImage!!.width, gameImage!!.height) - g.color = Color.BLACK - g.drawString("Game Frame", 20, 20) - // Add any additional rendering here - } finally { - g.dispose() + gameImage?.createGraphics()?.apply { + color = Color.RED + fillRect(0, 0, gameImage!!.width, gameImage!!.height) + color = Color.BLACK + drawString("Game Frame", 20, 20) + dispose() } } @@ -257,104 +219,58 @@ class plugin : Plugin() { g2d.color = Color.BLACK g2d.fillRect(0, 0, width, height) - // Validate image within paint to ensure compatibility with GraphicsConfiguration - var valid = false - do { - val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration - if (gameImage == null) { - gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) - renderGameImage() - } else { - val status = gameImage!!.validate(gc) - when (status) { - VolatileImage.IMAGE_INCOMPATIBLE -> { - gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) - renderGameImage() - } - VolatileImage.IMAGE_RESTORED -> renderGameImage() - VolatileImage.IMAGE_OK -> valid = true - } - } - } while (!valid) - - // Continue with rendering the image gameImage?.let { image -> g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) - // Scaling and centering - val imageAspect = image.width.toDouble() / image.height.toDouble() - val panelAspect = width.toDouble() / height.toDouble() - - val (drawWidth, drawHeight) = if (imageAspect > panelAspect) { - val newWidth = width - val newHeight = (width / imageAspect).toInt() - newWidth to newHeight - } else { - val newHeight = height - val newWidth = (height * imageAspect).toInt() - newWidth to newHeight - } - - // Store scale factors and offsets for event adjustment + val (drawWidth, drawHeight) = calculateDrawDimensions(image) scaleX = drawWidth.toDouble() / image.width scaleY = drawHeight.toDouble() / image.height offsetX = (width - drawWidth) / 2 offsetY = (height - drawHeight) / 2 + g2d.drawImage(image, offsetX, offsetY, drawWidth, drawHeight, null) + Toolkit.getDefaultToolkit().sync() + } + } - // Draw the scaled image centered in the panel - val x = offsetX - val y = offsetY - g2d.drawImage(image, x, y, drawWidth, drawHeight, null) - g2d.dispose() - //bufferStrategy.show() // Shows the buffer with V-Sync enabled - Toolkit.getDefaultToolkit().sync() // Ensures V-Sync on some systems + private fun calculateDrawDimensions(image: VolatileImage): Pair { + val imageAspect = image.width.toDouble() / image.height.toDouble() + val panelAspect = width.toDouble() / height.toDouble() + return if (imageAspect > panelAspect) { + width to (width / imageAspect).toInt() + } else { + (height * imageAspect).toInt() to height } } private fun relayMouseEvent(e: MouseEvent) { - this.requestFocusInWindow() - val adjustedX = (e.x - offsetX) / scaleX - val adjustedY = (e.y - offsetY) / scaleY + requestFocusInWindow() + val adjustedX = ((e.x - offsetX) / scaleX).toInt().coerceIn(0, gameImage!!.width - 1) + val adjustedY = ((e.y - offsetY) / scaleY).toInt().coerceIn(0, gameImage!!.height - 1) + canvas.dispatchEvent(MouseEvent(canvas, e.id, e.`when`, e.modifiersEx, adjustedX, adjustedY, e.clickCount, e.isPopupTrigger, e.button)) + } - val originalX = adjustedX.toInt().coerceIn(0, gameImage!!.width - 1) - val originalY = adjustedY.toInt().coerceIn(0, gameImage!!.height - 1) - - val newEvent = MouseEvent( - canvas, e.id, e.`when`, e.modifiersEx, - originalX, originalY, e.clickCount, e.isPopupTrigger, e.button - ) - canvas.dispatchEvent(newEvent) + private fun relayKeyEvent(e: KeyEvent, action: (KeyListener) -> Unit) { + for (listener in canvas.keyListeners) action(listener) } fun updateGameImage() { - if(this.parent == null) { - println("Unparented.. skipping update.") - } - validateGameImage() - if (IsHD()) { - renderGlRaster() - } else { - renderSoftwareRaster() - } + if (IsHD()) renderGlRaster() else renderSoftwareRaster() repaint() } + private fun renderGlRaster() { - if (flippedPixels == null || flippedPixels!!.size != gameImage!!.width * gameImage!!.height) { - flippedPixels = IntArray(gameImage!!.width * gameImage!!.height) - } - - // Initialize bufferImage only once and reuse it - if (bufferImage == null || bufferImage!!.width != gameImage!!.width || bufferImage!!.height != gameImage!!.height) { - bufferImage = BufferedImage(gameImage!!.width, gameImage!!.height, BufferedImage.TYPE_INT_BGR) - } - val width = gameImage!!.width val height = gameImage!!.height - val pixels = GlRenderer.pixelData // Retrieve BGRA pixel data + val pixelData = GlRenderer.pixelData + + // Flip and copy pixels in one pass using a single loop for (y in 0 until height) { - System.arraycopy(pixels, (height - 1 - y) * width, flippedPixels, y * width, width) + val srcOffset = (height - 1 - y) * width + val destOffset = y * width + System.arraycopy(pixelData, srcOffset, flippedPixels, destOffset, width) } - bufferImage!!.setRGB(0, 0, width, height, flippedPixels, 0, width) + // Draw flipped pixels directly to bufferImage + bufferImage.setRGB(0, 0, width, height, flippedPixels, 0, width) gameImage?.createGraphics()?.apply { drawImage(bufferImage, 0, 0, null) @@ -363,23 +279,19 @@ class plugin : Plugin() { } private fun renderSoftwareRaster() { - val g = gameImage!!.createGraphics() - try { - SoftwareRaster.frameBuffer.draw(g) - } finally { - g.dispose() + gameImage?.createGraphics()?.apply { + SoftwareRaster.frameBuffer.draw(this) + dispose() } } } - fun createAltCanvas(): AltCanvas { + private fun createAltCanvas(): AltCanvas { return AltCanvas().apply { preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) } } - private var altCanvas: AltCanvas? = null - override fun Init() { // Disable Font AA @@ -552,6 +464,14 @@ class plugin : Plugin() { override fun LateDraw(timeDelta: Long) { if (!initialized) return + if(GameShell.fullScreenFrame != null) { + DisplayMode.setWindowMode(true, 0, FIXED_WIDTH, FIXED_HEIGHT) + showAlert("Fullscreen is not supported by KondoKit. Disable the plugin", + "Error", + JOptionPane.INFORMATION_MESSAGE + ) + return; + } if(GetWindowMode() == WindowMode.RESIZABLE){ frame.setComponentZOrder(altCanvas, 1) frame.setComponentZOrder(canvas, 0) @@ -708,22 +628,18 @@ class plugin : Plugin() { val elapsedTime = (System.currentTimeMillis() - xpWidget.startTime) / 1000.0 / 60.0 / 60.0 val xpPerHour = if (elapsedTime > 0) (xpWidget.totalXpGained / elapsedTime).toInt() else 0 val formattedXpPerHour = formatNumber(xpPerHour) - SwingUtilities.invokeLater{ - xpWidget.xpPerHourLabel.text = - formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) - xpWidget.container.repaint() - } + xpWidget.xpPerHourLabel.text = + formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) + xpWidget.container.repaint() } totalXP?.let { totalXPWidget -> val elapsedTime = (System.currentTimeMillis() - totalXPWidget.startTime) / 1000.0 / 60.0 / 60.0 val totalXPPerHour = if (elapsedTime > 0) (totalXPWidget.totalXpGained / elapsedTime).toInt() else 0 val formattedTotalXpPerHour = formatNumber(totalXPPerHour) - SwingUtilities.invokeLater{ - totalXPWidget.xpPerHourLabel.text = - formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) - totalXPWidget.container.repaint() - } + totalXPWidget.xpPerHourLabel.text = + formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) + totalXPWidget.container.repaint() } } From c5ba4ecc94a2361f6d6562c32b0c1076b3117b74 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 27 Oct 2024 20:11:25 -0700 Subject: [PATCH 35/47] true nn upscale --- .../src/main/kotlin/KondoKit/plugin.kt | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index a16e748..aa3c242 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -43,6 +43,8 @@ import rt4.client.mainLoadState import java.awt.* import java.awt.Font import java.awt.event.* +import java.awt.geom.AffineTransform +import java.awt.image.AffineTransformOp import java.awt.image.BufferedImage import java.awt.image.VolatileImage import javax.swing.* @@ -153,12 +155,7 @@ class plugin : Plugin() { class AltCanvas : Canvas() { private var gameImage: VolatileImage? = null - private var flippedPixels = IntArray(FIXED_WIDTH * FIXED_HEIGHT) private var bufferImage = BufferedImage(FIXED_WIDTH, FIXED_HEIGHT, BufferedImage.TYPE_INT_BGR) - private var scaleX = 1.0 - private var scaleY = 1.0 - private var offsetX = 0 - private var offsetY = 0 init { isFocusable = true @@ -220,13 +217,10 @@ class plugin : Plugin() { g2d.fillRect(0, 0, width, height) gameImage?.let { image -> - g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) - val (drawWidth, drawHeight) = calculateDrawDimensions(image) - scaleX = drawWidth.toDouble() / image.width - scaleY = drawHeight.toDouble() / image.height - offsetX = (width - drawWidth) / 2 - offsetY = (height - drawHeight) / 2 - g2d.drawImage(image, offsetX, offsetY, drawWidth, drawHeight, null) + val scale = minOf(width.toDouble() / image.width, height.toDouble() / image.height) + val x = ((width - image.width * scale) / 2).toInt() + val y = ((height - image.height * scale) / 2).toInt() + g2d.drawImage(image, x, y, (image.width * scale).toInt(), (image.height * scale).toInt(), null) Toolkit.getDefaultToolkit().sync() } } @@ -243,9 +237,14 @@ class plugin : Plugin() { private fun relayMouseEvent(e: MouseEvent) { requestFocusInWindow() - val adjustedX = ((e.x - offsetX) / scaleX).toInt().coerceIn(0, gameImage!!.width - 1) - val adjustedY = ((e.y - offsetY) / scaleY).toInt().coerceIn(0, gameImage!!.height - 1) - canvas.dispatchEvent(MouseEvent(canvas, e.id, e.`when`, e.modifiersEx, adjustedX, adjustedY, e.clickCount, e.isPopupTrigger, e.button)) + val scale = minOf(width.toDouble() / gameImage!!.width, height.toDouble() / gameImage!!.height) + val xOffset = ((width - gameImage!!.width * scale) / 2) + val yOffset = ((height - gameImage!!.height * scale) / 2) + + val adjustedX = ((e.x - xOffset) / scale).toInt().coerceIn(0, gameImage!!.width - 1) + val adjustedY = ((e.y - yOffset) / scale).toInt().coerceIn(0, gameImage!!.height - 1) + + canvas.dispatchEvent(MouseEvent(this, e.id, e.`when`, e.modifiersEx, adjustedX, adjustedY, e.clickCount, e.isPopupTrigger, e.button)) } private fun relayKeyEvent(e: KeyEvent, action: (KeyListener) -> Unit) { @@ -262,22 +261,20 @@ class plugin : Plugin() { val height = gameImage!!.height val pixelData = GlRenderer.pixelData - // Flip and copy pixels in one pass using a single loop - for (y in 0 until height) { - val srcOffset = (height - 1 - y) * width - val destOffset = y * width - System.arraycopy(pixelData, srcOffset, flippedPixels, destOffset, width) - } + bufferImage.setRGB(0, 0, width, height, pixelData, 0, width) - // Draw flipped pixels directly to bufferImage - bufferImage.setRGB(0, 0, width, height, flippedPixels, 0, width) + val transform = AffineTransform.getScaleInstance(1.0, -1.0) + transform.translate(0.0, -height.toDouble()) + val op = AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR) + val flippedImage = op.filter(bufferImage, null) gameImage?.createGraphics()?.apply { - drawImage(bufferImage, 0, 0, null) + drawImage(flippedImage, 0, 0, null) dispose() } } + private fun renderSoftwareRaster() { gameImage?.createGraphics()?.apply { SoftwareRaster.frameBuffer.draw(this) From 8b89a2bb8c68a712fb61c7df707ed8342541c975 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 27 Oct 2024 20:22:16 -0700 Subject: [PATCH 36/47] Faster transforms --- .../src/main/kotlin/KondoKit/plugin.kt | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index aa3c242..8ee2e9f 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -155,8 +155,15 @@ class plugin : Plugin() { class AltCanvas : Canvas() { private var gameImage: VolatileImage? = null + private var op: AffineTransformOp? = null + private var transform: AffineTransform? = null + + private var flippedImage: BufferedImage? = null // Only used in HD private var bufferImage = BufferedImage(FIXED_WIDTH, FIXED_HEIGHT, BufferedImage.TYPE_INT_BGR) + private var lastImageWidth = -1 + private var lastImageHeight = -1 + init { isFocusable = true requestFocusInWindow() @@ -225,16 +232,6 @@ class plugin : Plugin() { } } - private fun calculateDrawDimensions(image: VolatileImage): Pair { - val imageAspect = image.width.toDouble() / image.height.toDouble() - val panelAspect = width.toDouble() / height.toDouble() - return if (imageAspect > panelAspect) { - width to (width / imageAspect).toInt() - } else { - (height * imageAspect).toInt() to height - } - } - private fun relayMouseEvent(e: MouseEvent) { requestFocusInWindow() val scale = minOf(width.toDouble() / gameImage!!.width, height.toDouble() / gameImage!!.height) @@ -259,22 +256,32 @@ class plugin : Plugin() { private fun renderGlRaster() { val width = gameImage!!.width val height = gameImage!!.height - val pixelData = GlRenderer.pixelData - bufferImage.setRGB(0, 0, width, height, pixelData, 0, width) + bufferImage.setRGB(0, 0, width, height, GlRenderer.pixelData, 0, width) - val transform = AffineTransform.getScaleInstance(1.0, -1.0) - transform.translate(0.0, -height.toDouble()) - val op = AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR) - val flippedImage = op.filter(bufferImage, null) + // Check if dimensions have changed + if (width != lastImageWidth || height != lastImageHeight) { + // Initialize or update transform and operation + transform = AffineTransform.getScaleInstance(1.0, -1.0).apply { + translate(0.0, -height.toDouble()) + } + op = AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR) + flippedImage = BufferedImage(width, height, bufferImage.type) + lastImageWidth = width + lastImageHeight = height + } + + // Apply the transform operation + op!!.filter(bufferImage, flippedImage) + + // Draw the flipped image onto gameImage gameImage?.createGraphics()?.apply { drawImage(flippedImage, 0, 0, null) dispose() } } - private fun renderSoftwareRaster() { gameImage?.createGraphics()?.apply { SoftwareRaster.frameBuffer.draw(this) From c307db1e11f2744f57cff2d6e316b368f36c92a8 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 27 Oct 2024 21:38:12 -0700 Subject: [PATCH 37/47] double buffering --- .../src/main/kotlin/KondoKit/plugin.kt | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 8ee2e9f..9e7f325 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -158,7 +158,7 @@ class plugin : Plugin() { private var op: AffineTransformOp? = null private var transform: AffineTransform? = null - private var flippedImage: BufferedImage? = null // Only used in HD + private var flippedImage: BufferedImage? = null private var bufferImage = BufferedImage(FIXED_WIDTH, FIXED_HEIGHT, BufferedImage.TYPE_INT_BGR) private var lastImageWidth = -1 @@ -190,6 +190,7 @@ class plugin : Plugin() { override fun addNotify() { super.addNotify() + createBufferStrategy(2) // Double-buffering validateGameImage() } @@ -218,17 +219,23 @@ class plugin : Plugin() { } } - override fun paint(g: Graphics) { - val g2d = g as Graphics2D - g2d.color = Color.BLACK - g2d.fillRect(0, 0, width, height) - gameImage?.let { image -> - val scale = minOf(width.toDouble() / image.width, height.toDouble() / image.height) - val x = ((width - image.width * scale) / 2).toInt() - val y = ((height - image.height * scale) / 2).toInt() - g2d.drawImage(image, x, y, (image.width * scale).toInt(), (image.height * scale).toInt(), null) - Toolkit.getDefaultToolkit().sync() + override fun paint(g: Graphics) { + bufferStrategy?.let { strategy -> + val g2d = strategy.drawGraphics as? Graphics2D ?: return + + g2d.color = Color.BLACK + g2d.fillRect(0, 0, width, height) + + gameImage?.let { image -> + val scale = minOf(width.toDouble() / image.width, height.toDouble() / image.height) + val x = ((width - image.width * scale) / 2).toInt() + val y = ((height - image.height * scale) / 2).toInt() + g2d.drawImage(image, x, y, (image.width * scale).toInt(), (image.height * scale).toInt(), null) + } + + g2d.dispose() // Release the graphics context + strategy.show() // Display the buffer } } @@ -259,23 +266,18 @@ class plugin : Plugin() { bufferImage.setRGB(0, 0, width, height, GlRenderer.pixelData, 0, width) - // Check if dimensions have changed if (width != lastImageWidth || height != lastImageHeight) { - // Initialize or update transform and operation transform = AffineTransform.getScaleInstance(1.0, -1.0).apply { translate(0.0, -height.toDouble()) } op = AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR) flippedImage = BufferedImage(width, height, bufferImage.type) - lastImageWidth = width lastImageHeight = height } - // Apply the transform operation op!!.filter(bufferImage, flippedImage) - // Draw the flipped image onto gameImage gameImage?.createGraphics()?.apply { drawImage(flippedImage, 0, 0, null) dispose() From 07f4dc9349fba9112b1bca66256bc58295b728c3 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 28 Oct 2024 00:03:43 -0700 Subject: [PATCH 38/47] mostly working alt canvas --- .../src/main/kotlin/KondoKit/plugin.kt | 231 ++++++++++-------- 1 file changed, 135 insertions(+), 96 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 9e7f325..f6ab697 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -93,6 +93,9 @@ class plugin : Plugin() { "perfectly snapped to the edge of the game due to window chrome you can update this to fix it") var uiOffset = 0 + @Exposed("Stretched/Scaled Fixed Mode Support") + var useAltCanvas = false + private const val FIXED_WIDTH = 765 private const val FIXED_HEIGHT = 503 private const val NAVBAR_WIDTH = 30 @@ -113,6 +116,7 @@ class plugin : Plugin() { private var initialized = false private var lastClickTime = 0L private var lastUIOffset = 0 + private var themeName = "RUNELITE" private const val HIDDEN_VIEW = "HIDDEN" private var altCanvas: AltCanvas? = null private val drawActions = mutableListOf<() -> Unit>() @@ -292,27 +296,22 @@ class plugin : Plugin() { } } - private fun createAltCanvas(): AltCanvas { - return AltCanvas().apply { - preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) - } - } - override fun Init() { // Disable Font AA System.setProperty("sun.java2d.opengl", "false") System.setProperty("awt.useSystemAAFontSettings", "off") System.setProperty("swing.aatext", "false") - val frame: Frame? = GameShell.frame + } + + private fun InitAltCanvas(){ if (frame != null) { - frame.layout = BorderLayout() - // Create the AltCanvas and add it to the main frame - altCanvas = createAltCanvas() + altCanvas = AltCanvas().apply { + preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) + } altCanvas?.let { frame.add(it) } - // Use BorderLayout for better layout control - frame.setComponentZOrder(altCanvas, 0) - frame.setComponentZOrder(canvas, 1) + moveAltCanvasToFront() + frame.setComponentZOrder(rightPanelWrapper, 2) } } @@ -325,9 +324,15 @@ class plugin : Plugin() { if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + uiOffset) { frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + uiOffset, frame.height) } - canvas.setLocation(0,0) val difference = frame.width - (uiOffset + currentScrollPaneWidth) - altCanvas?.size = Dimension(difference, frame.height - 30) + if(useAltCanvas){ + GameShell.leftMargin = 0 + canvas.setLocation(0,canvas.y) + altCanvas?.size = Dimension(difference, frame.height - canvas.y) + } else { + GameShell.leftMargin = difference / 2 + canvas.setLocation(GameShell.leftMargin - (FIXED_WIDTH/2), canvas.y) + } } WindowMode.RESIZABLE -> { GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + uiOffset) @@ -353,6 +358,15 @@ class plugin : Plugin() { LootTrackerView.gePriceMap = LootTrackerView.loadGEPrices() StoreData("kondoLaunchMinimized", launchMinimized) StoreData("kondoUIOffset", uiOffset) + StoreData("kondoScaleFixed", useAltCanvas) + if(altCanvas == null && useAltCanvas){ + InitAltCanvas() + UpdateDisplaySettings() + } else if(altCanvas != null && !useAltCanvas){ + frame.remove(altCanvas) + altCanvas = null + UpdateDisplaySettings() + } if(lastUIOffset != uiOffset){ UpdateDisplaySettings() reloadInterfaces = true @@ -472,99 +486,60 @@ class plugin : Plugin() { if (!initialized) return if(GameShell.fullScreenFrame != null) { DisplayMode.setWindowMode(true, 0, FIXED_WIDTH, FIXED_HEIGHT) - showAlert("Fullscreen is not supported by KondoKit. Disable the plugin", + showAlert("Fullscreen is not supported by KondoKit. Disable the plugin first.", "Error", JOptionPane.INFORMATION_MESSAGE ) - return; + return } + if(!useAltCanvas) return if(GetWindowMode() == WindowMode.RESIZABLE){ - frame.setComponentZOrder(altCanvas, 1) - frame.setComponentZOrder(canvas, 0) + moveAltCanvasToFront() } else { - frame.setComponentZOrder(altCanvas, 0) - frame.setComponentZOrder(canvas, 1) + moveCanvasToFront() } altCanvas?.updateGameImage() // Update the game image as needed } + private fun moveAltCanvasToFront(){ + if(altCanvas == null) { + println("WARNING: altcanvas is null") + return + } + frame.setComponentZOrder(altCanvas, 1) + frame.setComponentZOrder(canvas, 0) + } + + private fun moveCanvasToFront(){ + if(altCanvas == null) { + println("WARNING: altcanvas is null") + return + } + frame.setComponentZOrder(altCanvas, 0) + frame.setComponentZOrder(canvas, 1) + } + + private fun restoreSettings(){ + themeName = (GetData("kondoTheme") as? String) ?: "RUNELITE" + useLiveGEPrices = (GetData("kondoUseRemoteGE") as? Boolean) ?: true + playerXPMultiplier = (GetData("kondoPlayerXPMultiplier") as? Int) ?: 5 + val osName = System.getProperty("os.name").toLowerCase() + uiOffset = (GetData("kondoUIOffset") as? Int) ?: if (osName.contains("win")) 16 else 0 + launchMinimized = (GetData("kondoLaunchMinimized") as? Boolean) ?: false + useAltCanvas = (GetData("kondoScaleFixed") as? Boolean) ?: false + } + private fun initKondoUI(){ DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) if(!allSpritesLoaded()) return; val frame: Frame? = GameShell.frame if (frame != null) { - + restoreSettings() loadFont() - val themeIndex = (GetData("kondoTheme") as? String) ?: "RUNELITE" - theme = ThemeType.valueOf(themeIndex) + theme = ThemeType.valueOf(themeName) applyTheme(getTheme(theme)) appliedTheme = theme - - try { - UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel") - - // Modify the UI properties to match theme - UIManager.put("control", VIEW_BACKGROUND_COLOR) - UIManager.put("info", VIEW_BACKGROUND_COLOR) - UIManager.put("nimbusBase", WIDGET_COLOR) - UIManager.put("nimbusBlueGrey", TITLE_BAR_COLOR) - - UIManager.put("nimbusDisabledText", primaryColor) - UIManager.put("nimbusSelectedText", secondaryColor) - UIManager.put("text", secondaryColor) - - UIManager.put("nimbusFocus", TITLE_BAR_COLOR) - UIManager.put("nimbusInfoBlue", POPUP_BACKGROUND) - UIManager.put("nimbusLightBackground", WIDGET_COLOR) - UIManager.put("nimbusSelectionBackground", PROGRESS_BAR_FILL) - - UIManager.put("Button.background", WIDGET_COLOR) - UIManager.put("Button.foreground", secondaryColor) - - UIManager.put("CheckBox.background", VIEW_BACKGROUND_COLOR) - UIManager.put("CheckBox.foreground", secondaryColor) - UIManager.put("CheckBox.icon", UIManager.getIcon("CheckBox.icon")) - - UIManager.put("ComboBox.background", WIDGET_COLOR) - UIManager.put("ComboBox.foreground", secondaryColor) - UIManager.put("ComboBox.selectionBackground", PROGRESS_BAR_FILL) - UIManager.put("ComboBox.selectionForeground", primaryColor) - UIManager.put("ComboBox.buttonBackground", WIDGET_COLOR) - - UIManager.put("Spinner.background", WIDGET_COLOR) - UIManager.put("Spinner.foreground", secondaryColor) - UIManager.put("Spinner.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) - - UIManager.put("TextField.background", WIDGET_COLOR) - UIManager.put("TextField.foreground", secondaryColor) - UIManager.put("TextField.caretForeground", secondaryColor) - UIManager.put("TextField.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) - - UIManager.put("ScrollBar.thumb", WIDGET_COLOR) - UIManager.put("ScrollBar.track", VIEW_BACKGROUND_COLOR) - UIManager.put("ScrollBar.thumbHighlight", TITLE_BAR_COLOR) - - UIManager.put("ProgressBar.foreground", PROGRESS_BAR_FILL) - UIManager.put("ProgressBar.background", WIDGET_COLOR) - UIManager.put("ProgressBar.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) - - UIManager.put("ToolTip.background", VIEW_BACKGROUND_COLOR) - UIManager.put("ToolTip.foreground", secondaryColor) - UIManager.put("ToolTip.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) - - // Update component tree UI to apply the new theme - SwingUtilities.updateComponentTreeUI(GameShell.frame) - GameShell.frame.background = Color.BLACK - } catch (e : Exception) { - e.printStackTrace() - } - - // Restore saved values - useLiveGEPrices = (GetData("kondoUseRemoteGE") as? Boolean) ?: true - playerXPMultiplier = (GetData("kondoPlayerXPMultiplier") as? Int) ?: 5 - val osName = System.getProperty("os.name").toLowerCase() - uiOffset = (GetData("kondoUIOffset") as? Int) ?: if (osName.contains("win")) 16 else 0 - launchMinimized = (GetData("kondoLaunchMinimized") as? Boolean) ?: false + configureLookAndFeel() cardLayout = CardLayout() mainContentPanel = JPanel(cardLayout).apply { @@ -596,7 +571,7 @@ class plugin : Plugin() { navPanel.add(createNavButton(LOOT_ICON, LootTrackerView.VIEW_NAME)) navPanel.add(createNavButton(WRENCH_ICON, ReflectiveEditorView.VIEW_NAME)) - var rightPanel = Panel(BorderLayout()).apply { + val rightPanel = Panel(BorderLayout()).apply { add(mainContentPanel, BorderLayout.CENTER) add(navPanel, BorderLayout.EAST) } @@ -604,7 +579,7 @@ class plugin : Plugin() { rightPanelWrapper = JScrollPane(rightPanel).apply { preferredSize = Dimension(NAVBAR_WIDTH + MAIN_CONTENT_WIDTH, frame.height) background = VIEW_BACKGROUND_COLOR - border = BorderFactory.createEmptyBorder() // Removes the border completely + border = BorderFactory.createEmptyBorder() horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_NEVER } @@ -612,13 +587,16 @@ class plugin : Plugin() { frame.layout = BorderLayout() rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) - frame.setComponentZOrder(it, 2) } - if(!launchMinimized){ - setActiveView(XPTrackerView.VIEW_NAME) - } else { + if(launchMinimized){ setActiveView(HIDDEN_VIEW) + } else { + setActiveView(XPTrackerView.VIEW_NAME) + } + if(useAltCanvas) { + InitAltCanvas() + UpdateDisplaySettings() } initialized = true pluginsReloaded = true @@ -761,6 +739,67 @@ class plugin : Plugin() { return panelButton } + private fun configureLookAndFeel(){ + try { + UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel") + + // Modify the UI properties to match theme + UIManager.put("control", VIEW_BACKGROUND_COLOR) + UIManager.put("info", VIEW_BACKGROUND_COLOR) + UIManager.put("nimbusBase", WIDGET_COLOR) + UIManager.put("nimbusBlueGrey", TITLE_BAR_COLOR) + + UIManager.put("nimbusDisabledText", primaryColor) + UIManager.put("nimbusSelectedText", secondaryColor) + UIManager.put("text", secondaryColor) + + UIManager.put("nimbusFocus", TITLE_BAR_COLOR) + UIManager.put("nimbusInfoBlue", POPUP_BACKGROUND) + UIManager.put("nimbusLightBackground", WIDGET_COLOR) + UIManager.put("nimbusSelectionBackground", PROGRESS_BAR_FILL) + + UIManager.put("Button.background", WIDGET_COLOR) + UIManager.put("Button.foreground", secondaryColor) + + UIManager.put("CheckBox.background", VIEW_BACKGROUND_COLOR) + UIManager.put("CheckBox.foreground", secondaryColor) + UIManager.put("CheckBox.icon", UIManager.getIcon("CheckBox.icon")) + + UIManager.put("ComboBox.background", WIDGET_COLOR) + UIManager.put("ComboBox.foreground", secondaryColor) + UIManager.put("ComboBox.selectionBackground", PROGRESS_BAR_FILL) + UIManager.put("ComboBox.selectionForeground", primaryColor) + UIManager.put("ComboBox.buttonBackground", WIDGET_COLOR) + + UIManager.put("Spinner.background", WIDGET_COLOR) + UIManager.put("Spinner.foreground", secondaryColor) + UIManager.put("Spinner.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) + + UIManager.put("TextField.background", WIDGET_COLOR) + UIManager.put("TextField.foreground", secondaryColor) + UIManager.put("TextField.caretForeground", secondaryColor) + UIManager.put("TextField.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) + + UIManager.put("ScrollBar.thumb", WIDGET_COLOR) + UIManager.put("ScrollBar.track", VIEW_BACKGROUND_COLOR) + UIManager.put("ScrollBar.thumbHighlight", TITLE_BAR_COLOR) + + UIManager.put("ProgressBar.foreground", PROGRESS_BAR_FILL) + UIManager.put("ProgressBar.background", WIDGET_COLOR) + UIManager.put("ProgressBar.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) + + UIManager.put("ToolTip.background", VIEW_BACKGROUND_COLOR) + UIManager.put("ToolTip.foreground", secondaryColor) + UIManager.put("ToolTip.border", BorderFactory.createLineBorder(TITLE_BAR_COLOR)) + + // Update component tree UI to apply the new theme + SwingUtilities.updateComponentTreeUI(frame) + frame.background = Color.BLACK + } catch (e : Exception) { + e.printStackTrace() + } + } + fun loadFont(): Font? { val fontStream = plugin::class.java.getResourceAsStream("res/runescape_small.ttf") From c24df5ab46e53b912075a0ddabc51c078a512357 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 28 Oct 2024 07:18:08 -0700 Subject: [PATCH 39/47] cleanup files --- .../src/main/kotlin/KondoKit/AltCanvas.kt | 153 +++++++++++++++++ .../src/main/kotlin/KondoKit/plugin.kt | 161 +----------------- 2 files changed, 162 insertions(+), 152 deletions(-) create mode 100644 plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt diff --git a/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt b/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt new file mode 100644 index 0000000..cf3279d --- /dev/null +++ b/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt @@ -0,0 +1,153 @@ +package KondoKit + +import KondoKit.plugin.Companion.FIXED_HEIGHT +import KondoKit.plugin.Companion.FIXED_WIDTH +import plugin.api.API.IsHD +import rt4.GameShell.canvas +import rt4.GlRenderer +import rt4.SoftwareRaster +import java.awt.* +import java.awt.event.* +import java.awt.geom.AffineTransform +import java.awt.image.AffineTransformOp +import java.awt.image.BufferedImage +import java.awt.image.VolatileImage + +class AltCanvas : Canvas() { + private var gameImage: VolatileImage? = null + private var op: AffineTransformOp? = null + private var transform: AffineTransform? = null + + private var flippedImage: BufferedImage? = null + private var bufferImage = BufferedImage(FIXED_WIDTH, FIXED_HEIGHT, BufferedImage.TYPE_INT_BGR) + + private var lastImageWidth = -1 + private var lastImageHeight = -1 + + init { + isFocusable = true + requestFocusInWindow() + + addMouseListener(object : MouseAdapter() { + override fun mousePressed(e: MouseEvent) = relayMouseEvent(e) + override fun mouseReleased(e: MouseEvent) = relayMouseEvent(e) + override fun mouseClicked(e: MouseEvent) = relayMouseEvent(e) + }) + + addMouseMotionListener(object : MouseMotionAdapter() { + override fun mouseMoved(e: MouseEvent) = relayMouseEvent(e) + override fun mouseDragged(e: MouseEvent) = relayMouseEvent(e) + }) + + addKeyListener(object : KeyAdapter() { + override fun keyPressed(e: KeyEvent) = relayKeyEvent(e) { it.keyPressed(e) } + override fun keyReleased(e: KeyEvent) = relayKeyEvent(e) { it.keyReleased(e) } + override fun keyTyped(e: KeyEvent) = relayKeyEvent(e) { it.keyTyped(e) } + }) + } + + override fun update(g: Graphics) = paint(g) + + override fun addNotify() { + super.addNotify() + createBufferStrategy(2) // Double-buffering + validateGameImage() + } + + private fun validateGameImage() { + val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration + gameImage?.let { + when (it.validate(gc)) { + VolatileImage.IMAGE_INCOMPATIBLE -> createGameImage(gc) + VolatileImage.IMAGE_RESTORED -> renderGameImage() + } + } ?: createGameImage(gc) + } + + private fun createGameImage(gc: GraphicsConfiguration) { + gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) + renderGameImage() + } + + private fun renderGameImage() { + gameImage?.createGraphics()?.apply { + color = Color.DARK_GRAY + fillRect(0, 0, gameImage!!.width, gameImage!!.height) + color = Color.BLACK + drawString("KondoKit Scaled Fixed Canvas", 20, 20) + dispose() + } + } + + + override fun paint(g: Graphics) { + bufferStrategy?.let { strategy -> + val g2d = strategy.drawGraphics as? Graphics2D ?: return + + g2d.color = Color.BLACK + g2d.fillRect(0, 0, width, height) + + gameImage?.let { image -> + val scale = minOf(width.toDouble() / image.width, height.toDouble() / image.height) + val x = ((width - image.width * scale) / 2).toInt() + val y = ((height - image.height * scale) / 2).toInt() + g2d.drawImage(image, x, y, (image.width * scale).toInt(), (image.height * scale).toInt(), null) + } + + g2d.dispose() // Release the graphics context + strategy.show() // Display the buffer + } + } + + private fun relayMouseEvent(e: MouseEvent) { + requestFocusInWindow() + val scale = minOf(width.toDouble() / gameImage!!.width, height.toDouble() / gameImage!!.height) + val xOffset = ((width - gameImage!!.width * scale) / 2) + val yOffset = ((height - gameImage!!.height * scale) / 2) + + val adjustedX = ((e.x - xOffset) / scale).toInt().coerceIn(0, gameImage!!.width - 1) + val adjustedY = ((e.y - yOffset) / scale).toInt().coerceIn(0, gameImage!!.height - 1) + + canvas.dispatchEvent(MouseEvent(this, e.id, e.`when`, e.modifiersEx, adjustedX, adjustedY, e.clickCount, e.isPopupTrigger, e.button)) + } + + private fun relayKeyEvent(e: KeyEvent, action: (KeyListener) -> Unit) { + for (listener in canvas.keyListeners) action(listener) + } + + fun updateGameImage() { + if (IsHD()) renderGlRaster() else renderSoftwareRaster() + repaint() + } + + private fun renderGlRaster() { + val width = gameImage!!.width + val height = gameImage!!.height + + bufferImage.setRGB(0, 0, width, height, GlRenderer.pixelData, 0, width) + + if (width != lastImageWidth || height != lastImageHeight) { + transform = AffineTransform.getScaleInstance(1.0, -1.0).apply { + translate(0.0, -height.toDouble()) + } + op = AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR) + flippedImage = BufferedImage(width, height, bufferImage.type) + lastImageWidth = width + lastImageHeight = height + } + + op!!.filter(bufferImage, flippedImage) + + gameImage?.createGraphics()?.apply { + drawImage(flippedImage, 0, 0, null) + dispose() + } + } + + private fun renderSoftwareRaster() { + gameImage?.createGraphics()?.apply { + SoftwareRaster.frameBuffer.draw(this) + dispose() + } + } +} \ No newline at end of file diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index f6ab697..4e3167c 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -42,11 +42,9 @@ import rt4.client.js5Archive8 import rt4.client.mainLoadState import java.awt.* import java.awt.Font -import java.awt.event.* -import java.awt.geom.AffineTransform -import java.awt.image.AffineTransformOp -import java.awt.image.BufferedImage -import java.awt.image.VolatileImage +import java.awt.event.ActionListener +import java.awt.event.MouseAdapter +import java.awt.event.MouseEvent import javax.swing.* @@ -96,8 +94,8 @@ class plugin : Plugin() { @Exposed("Stretched/Scaled Fixed Mode Support") var useAltCanvas = false - private const val FIXED_WIDTH = 765 - private const val FIXED_HEIGHT = 503 + const val FIXED_WIDTH = 765 + const val FIXED_HEIGHT = 503 private const val NAVBAR_WIDTH = 30 private const val MAIN_CONTENT_WIDTH = 242 private const val WRENCH_ICON = 907 @@ -157,146 +155,6 @@ class plugin : Plugin() { lastLogin = Player.usernameInput.toString() } - class AltCanvas : Canvas() { - private var gameImage: VolatileImage? = null - private var op: AffineTransformOp? = null - private var transform: AffineTransform? = null - - private var flippedImage: BufferedImage? = null - private var bufferImage = BufferedImage(FIXED_WIDTH, FIXED_HEIGHT, BufferedImage.TYPE_INT_BGR) - - private var lastImageWidth = -1 - private var lastImageHeight = -1 - - init { - isFocusable = true - requestFocusInWindow() - - addMouseListener(object : MouseAdapter() { - override fun mousePressed(e: MouseEvent) = relayMouseEvent(e) - override fun mouseReleased(e: MouseEvent) = relayMouseEvent(e) - override fun mouseClicked(e: MouseEvent) = relayMouseEvent(e) - }) - - addMouseMotionListener(object : MouseMotionAdapter() { - override fun mouseMoved(e: MouseEvent) = relayMouseEvent(e) - override fun mouseDragged(e: MouseEvent) = relayMouseEvent(e) - }) - - addKeyListener(object : KeyAdapter() { - override fun keyPressed(e: KeyEvent) = relayKeyEvent(e) { it.keyPressed(e) } - override fun keyReleased(e: KeyEvent) = relayKeyEvent(e) { it.keyReleased(e) } - override fun keyTyped(e: KeyEvent) = relayKeyEvent(e) { it.keyTyped(e) } - }) - } - - override fun update(g: Graphics) = paint(g) - - override fun addNotify() { - super.addNotify() - createBufferStrategy(2) // Double-buffering - validateGameImage() - } - - private fun validateGameImage() { - val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration - gameImage?.let { - when (it.validate(gc)) { - VolatileImage.IMAGE_INCOMPATIBLE -> createGameImage(gc) - VolatileImage.IMAGE_RESTORED -> renderGameImage() - } - } ?: createGameImage(gc) - } - - private fun createGameImage(gc: GraphicsConfiguration) { - gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE) - renderGameImage() - } - - private fun renderGameImage() { - gameImage?.createGraphics()?.apply { - color = Color.RED - fillRect(0, 0, gameImage!!.width, gameImage!!.height) - color = Color.BLACK - drawString("Game Frame", 20, 20) - dispose() - } - } - - - override fun paint(g: Graphics) { - bufferStrategy?.let { strategy -> - val g2d = strategy.drawGraphics as? Graphics2D ?: return - - g2d.color = Color.BLACK - g2d.fillRect(0, 0, width, height) - - gameImage?.let { image -> - val scale = minOf(width.toDouble() / image.width, height.toDouble() / image.height) - val x = ((width - image.width * scale) / 2).toInt() - val y = ((height - image.height * scale) / 2).toInt() - g2d.drawImage(image, x, y, (image.width * scale).toInt(), (image.height * scale).toInt(), null) - } - - g2d.dispose() // Release the graphics context - strategy.show() // Display the buffer - } - } - - private fun relayMouseEvent(e: MouseEvent) { - requestFocusInWindow() - val scale = minOf(width.toDouble() / gameImage!!.width, height.toDouble() / gameImage!!.height) - val xOffset = ((width - gameImage!!.width * scale) / 2) - val yOffset = ((height - gameImage!!.height * scale) / 2) - - val adjustedX = ((e.x - xOffset) / scale).toInt().coerceIn(0, gameImage!!.width - 1) - val adjustedY = ((e.y - yOffset) / scale).toInt().coerceIn(0, gameImage!!.height - 1) - - canvas.dispatchEvent(MouseEvent(this, e.id, e.`when`, e.modifiersEx, adjustedX, adjustedY, e.clickCount, e.isPopupTrigger, e.button)) - } - - private fun relayKeyEvent(e: KeyEvent, action: (KeyListener) -> Unit) { - for (listener in canvas.keyListeners) action(listener) - } - - fun updateGameImage() { - if (IsHD()) renderGlRaster() else renderSoftwareRaster() - repaint() - } - - private fun renderGlRaster() { - val width = gameImage!!.width - val height = gameImage!!.height - - bufferImage.setRGB(0, 0, width, height, GlRenderer.pixelData, 0, width) - - if (width != lastImageWidth || height != lastImageHeight) { - transform = AffineTransform.getScaleInstance(1.0, -1.0).apply { - translate(0.0, -height.toDouble()) - } - op = AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR) - flippedImage = BufferedImage(width, height, bufferImage.type) - lastImageWidth = width - lastImageHeight = height - } - - op!!.filter(bufferImage, flippedImage) - - gameImage?.createGraphics()?.apply { - drawImage(flippedImage, 0, 0, null) - dispose() - } - } - - private fun renderSoftwareRaster() { - gameImage?.createGraphics()?.apply { - SoftwareRaster.frameBuffer.draw(this) - dispose() - } - } - } - - override fun Init() { // Disable Font AA System.setProperty("sun.java2d.opengl", "false") @@ -313,6 +171,7 @@ class plugin : Plugin() { moveAltCanvasToFront() frame.setComponentZOrder(rightPanelWrapper, 2) } + UpdateDisplaySettings() } private fun UpdateDisplaySettings() { @@ -328,9 +187,9 @@ class plugin : Plugin() { if(useAltCanvas){ GameShell.leftMargin = 0 canvas.setLocation(0,canvas.y) - altCanvas?.size = Dimension(difference, frame.height - canvas.y) + altCanvas?.size = Dimension(difference + uiOffset/2, frame.height - canvas.y) } else { - GameShell.leftMargin = difference / 2 + GameShell.leftMargin = (difference + uiOffset) / 2 canvas.setLocation(GameShell.leftMargin - (FIXED_WIDTH/2), canvas.y) } } @@ -361,7 +220,6 @@ class plugin : Plugin() { StoreData("kondoScaleFixed", useAltCanvas) if(altCanvas == null && useAltCanvas){ InitAltCanvas() - UpdateDisplaySettings() } else if(altCanvas != null && !useAltCanvas){ frame.remove(altCanvas) altCanvas = null @@ -535,7 +393,6 @@ class plugin : Plugin() { val frame: Frame? = GameShell.frame if (frame != null) { restoreSettings() - loadFont() theme = ThemeType.valueOf(themeName) applyTheme(getTheme(theme)) appliedTheme = theme @@ -596,7 +453,6 @@ class plugin : Plugin() { } if(useAltCanvas) { InitAltCanvas() - UpdateDisplaySettings() } initialized = true pluginsReloaded = true @@ -740,6 +596,7 @@ class plugin : Plugin() { } private fun configureLookAndFeel(){ + loadFont() try { UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel") From f2d4c175699b76f04309e31ccb47ccea9aec7c97 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 28 Oct 2024 10:53:23 -0700 Subject: [PATCH 40/47] Correct offsets --- .../main/kotlin/KondoKit/LootTrackerView.kt | 2 +- .../src/main/kotlin/KondoKit/plugin.kt | 64 ++++++++++++------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt index 3a0fc14..5f1a35a 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt @@ -4,7 +4,6 @@ import KondoKit.Helpers.addMouseListenerToAll import KondoKit.Helpers.formatHtmlLabelText import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.XPTrackerView.wrappedWidget -import KondoKit.plugin.Companion.IMAGE_SIZE import KondoKit.plugin.Companion.POPUP_BACKGROUND import KondoKit.plugin.Companion.POPUP_FOREGROUND import KondoKit.plugin.Companion.TITLE_BAR_COLOR @@ -351,6 +350,7 @@ object LootTrackerView { ?.apply { val newValue = (getClientProperty("val") as? Int ?: 0) + valueOfNewDrops.toInt() text = "${formatValue(newValue)} gp" + foreground = primaryColor putClientProperty("val", newValue) revalidate() if(focusedView == VIEW_NAME) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 4e3167c..fc34967 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -92,7 +92,7 @@ class plugin : Plugin() { var uiOffset = 0 @Exposed("Stretched/Scaled Fixed Mode Support") - var useAltCanvas = false + var useScaledFixed = false const val FIXED_WIDTH = 765 const val FIXED_HEIGHT = 503 @@ -162,7 +162,7 @@ class plugin : Plugin() { System.setProperty("swing.aatext", "false") } - private fun InitAltCanvas(){ + private fun initAltCanvas(){ if (frame != null) { altCanvas = AltCanvas().apply { preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) @@ -178,27 +178,36 @@ class plugin : Plugin() { val mode = GetWindowMode() val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH lastUIOffset = uiOffset + when (mode) { WindowMode.FIXED -> { if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + uiOffset) { frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + uiOffset, frame.height) } + val difference = frame.width - (uiOffset + currentScrollPaneWidth) - if(useAltCanvas){ + + if (useScaledFixed) { GameShell.leftMargin = 0 - canvas.setLocation(0,canvas.y) - altCanvas?.size = Dimension(difference + uiOffset/2, frame.height - canvas.y) + val canvasWidth = difference + uiOffset / 2 + val canvasHeight = frame.height - canvas.y // Restricting height to frame height + + altCanvas?.size = Dimension(canvasWidth, canvasHeight) + altCanvas?.setLocation(0, canvas.y) + canvas.setLocation(0, canvas.y) } else { GameShell.leftMargin = (difference + uiOffset) / 2 - canvas.setLocation(GameShell.leftMargin - (FIXED_WIDTH/2), canvas.y) + canvas.setLocation(GameShell.leftMargin - (FIXED_WIDTH / 2), canvas.y) } } + WindowMode.RESIZABLE -> { GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + uiOffset) } } + rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) - rightPanelWrapper?.let { it.isDoubleBuffered = true } + rightPanelWrapper?.isDoubleBuffered = true rightPanelWrapper?.revalidate() rightPanelWrapper?.repaint() } @@ -217,13 +226,11 @@ class plugin : Plugin() { LootTrackerView.gePriceMap = LootTrackerView.loadGEPrices() StoreData("kondoLaunchMinimized", launchMinimized) StoreData("kondoUIOffset", uiOffset) - StoreData("kondoScaleFixed", useAltCanvas) - if(altCanvas == null && useAltCanvas){ - InitAltCanvas() - } else if(altCanvas != null && !useAltCanvas){ - frame.remove(altCanvas) - altCanvas = null - UpdateDisplaySettings() + StoreData("kondoScaledFixed", useScaledFixed) + if(altCanvas == null && useScaledFixed){ + initAltCanvas() + } else if(altCanvas != null && !useScaledFixed){ + destroyAltCanvas() } if(lastUIOffset != uiOffset){ UpdateDisplaySettings() @@ -231,6 +238,13 @@ class plugin : Plugin() { } } + private fun destroyAltCanvas(){ + moveCanvasToFront() + frame.remove(altCanvas) + altCanvas = null + UpdateDisplaySettings() + } + override fun OnMiniMenuCreate(currentEntries: Array?) { if (currentEntries != null) { for ((index, entry) in currentEntries.withIndex()) { @@ -350,8 +364,8 @@ class plugin : Plugin() { ) return } - if(!useAltCanvas) return - if(GetWindowMode() == WindowMode.RESIZABLE){ + if(!useScaledFixed) return + if(GetWindowMode() == WindowMode.FIXED){ moveAltCanvasToFront() } else { moveCanvasToFront() @@ -364,8 +378,10 @@ class plugin : Plugin() { println("WARNING: altcanvas is null") return } + frame.setComponentZOrder(canvas, 2) frame.setComponentZOrder(altCanvas, 1) - frame.setComponentZOrder(canvas, 0) + frame.setComponentZOrder(rightPanelWrapper, 0) + } private fun moveCanvasToFront(){ @@ -373,8 +389,9 @@ class plugin : Plugin() { println("WARNING: altcanvas is null") return } - frame.setComponentZOrder(altCanvas, 0) + frame.setComponentZOrder(altCanvas, 2) frame.setComponentZOrder(canvas, 1) + frame.setComponentZOrder(rightPanelWrapper, 0) } private fun restoreSettings(){ @@ -384,12 +401,12 @@ class plugin : Plugin() { val osName = System.getProperty("os.name").toLowerCase() uiOffset = (GetData("kondoUIOffset") as? Int) ?: if (osName.contains("win")) 16 else 0 launchMinimized = (GetData("kondoLaunchMinimized") as? Boolean) ?: false - useAltCanvas = (GetData("kondoScaleFixed") as? Boolean) ?: false + useScaledFixed = (GetData("kondoScaleFixed") as? Boolean) ?: false } private fun initKondoUI(){ DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) - if(!allSpritesLoaded()) return; + if(!allSpritesLoaded()) return val frame: Frame? = GameShell.frame if (frame != null) { restoreSettings() @@ -451,8 +468,8 @@ class plugin : Plugin() { } else { setActiveView(XPTrackerView.VIEW_NAME) } - if(useAltCanvas) { - InitAltCanvas() + if(useScaledFixed) { + initAltCanvas() } initialized = true pluginsReloaded = true @@ -558,7 +575,7 @@ class plugin : Plugin() { maximumSize = buttonSize minimumSize = buttonSize background = WIDGET_COLOR - isOpaque = true // Ensure background is painted + isOpaque = true val gbc = GridBagConstraints().apply { anchor = GridBagConstraints.CENTER @@ -657,7 +674,6 @@ class plugin : Plugin() { } } - fun loadFont(): Font? { val fontStream = plugin::class.java.getResourceAsStream("res/runescape_small.ttf") return if (fontStream != null) { From 52d07d57958a8ecf1dcd5eaad952142497982797 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 28 Oct 2024 11:42:37 -0700 Subject: [PATCH 41/47] add mousewheel relay --- .../src/main/kotlin/KondoKit/AltCanvas.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt b/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt index cf3279d..319e7f5 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt @@ -44,6 +44,10 @@ class AltCanvas : Canvas() { override fun keyReleased(e: KeyEvent) = relayKeyEvent(e) { it.keyReleased(e) } override fun keyTyped(e: KeyEvent) = relayKeyEvent(e) { it.keyTyped(e) } }) + + addMouseWheelListener(object : MouseWheelListener { + override fun mouseWheelMoved(e: MouseWheelEvent) = relayMouseWheelEvent(e) + }) } override fun update(g: Graphics) = paint(g) @@ -115,6 +119,17 @@ class AltCanvas : Canvas() { for (listener in canvas.keyListeners) action(listener) } + private fun relayMouseWheelEvent(e: MouseWheelEvent) { + val scale = minOf(width.toDouble() / gameImage!!.width, height.toDouble() / gameImage!!.height) + val xOffset = ((width - gameImage!!.width * scale) / 2) + val yOffset = ((height - gameImage!!.height * scale) / 2) + + val adjustedX = ((e.x - xOffset) / scale).toInt().coerceIn(0, gameImage!!.width - 1) + val adjustedY = ((e.y - yOffset) / scale).toInt().coerceIn(0, gameImage!!.height - 1) + + canvas.dispatchEvent(MouseWheelEvent(this, e.id, e.`when`, e.modifiersEx, adjustedX, adjustedY, e.clickCount, e.isPopupTrigger, e.scrollType, e.scrollAmount, e.wheelRotation)) + } + fun updateGameImage() { if (IsHD()) renderGlRaster() else renderSoftwareRaster() repaint() From 1cca6611eeb8f7b909e6576cf24060f71324db33 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 28 Oct 2024 12:43:29 -0700 Subject: [PATCH 42/47] general cleanup --- .../src/main/kotlin/KondoKit/AltCanvas.kt | 12 +++--- .../src/main/kotlin/KondoKit/Helpers.kt | 12 ++---- .../src/main/kotlin/KondoKit/HiscoresView.kt | 14 +++---- .../main/kotlin/KondoKit/LootTrackerView.kt | 14 +++---- .../kotlin/KondoKit/ReflectiveEditorView.kt | 4 +- .../kotlin/KondoKit/SpriteToBufferedImage.kt | 12 +++--- .../src/main/kotlin/KondoKit/XPTable.kt | 6 +-- .../src/main/kotlin/KondoKit/plugin.kt | 37 ++++++++----------- 8 files changed, 46 insertions(+), 65 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt b/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt index 319e7f5..af5c01d 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt @@ -40,14 +40,12 @@ class AltCanvas : Canvas() { }) addKeyListener(object : KeyAdapter() { - override fun keyPressed(e: KeyEvent) = relayKeyEvent(e) { it.keyPressed(e) } - override fun keyReleased(e: KeyEvent) = relayKeyEvent(e) { it.keyReleased(e) } - override fun keyTyped(e: KeyEvent) = relayKeyEvent(e) { it.keyTyped(e) } + override fun keyPressed(e: KeyEvent) = relayKeyEvent { it.keyPressed(e) } + override fun keyReleased(e: KeyEvent) = relayKeyEvent { it.keyReleased(e) } + override fun keyTyped(e: KeyEvent) = relayKeyEvent { it.keyTyped(e) } }) - addMouseWheelListener(object : MouseWheelListener { - override fun mouseWheelMoved(e: MouseWheelEvent) = relayMouseWheelEvent(e) - }) + addMouseWheelListener(MouseWheelListener { e -> relayMouseWheelEvent(e) }) } override fun update(g: Graphics) = paint(g) @@ -115,7 +113,7 @@ class AltCanvas : Canvas() { canvas.dispatchEvent(MouseEvent(this, e.id, e.`when`, e.modifiersEx, adjustedX, adjustedY, e.clickCount, e.isPopupTrigger, e.button)) } - private fun relayKeyEvent(e: KeyEvent, action: (KeyListener) -> Unit) { + private fun relayKeyEvent(action: (KeyListener) -> Unit) { for (listener in canvas.keyListeners) action(listener) } diff --git a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt index 67530e3..4f6e3c4 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt @@ -95,10 +95,8 @@ object Helpers { } - - fun convertToColor(value: String): Color { - val color = Color.decode(value) // Assumes value is in format "#RRGGBB" or "0xRRGGBB" - return color + private fun convertToColor(value: String): Color { + return Color.decode(value) } fun colorToHex(color: Color): String { @@ -134,11 +132,7 @@ object Helpers { class FieldNotifier(private val plugin: Any) { private val observers = mutableListOf() - fun addObserver(observer: FieldObserver) { - observers.add(observer) - } - - fun notifyFieldChange(field: Field, newValue: Any?) { + private fun notifyFieldChange(field: Field, newValue: Any?) { for (observer in observers) { observer.onFieldChange(field, newValue) } diff --git a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt index f192098..0b48ab3 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt @@ -75,8 +75,8 @@ object HiscoresView { private var cursorVisible: Boolean = true private val gson = Gson() - val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.MAG_SPRITE)) - val imageCanvas = bufferedImageSprite.let { + private val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.MAG_SPRITE)) + private val imageCanvas = bufferedImageSprite.let { ImageCanvas(it).apply { preferredSize = Constants.ICON_DIMENSION_SMALL size = preferredSize @@ -241,7 +241,7 @@ object HiscoresView { playerNameLabel?.revalidate() playerNameLabel?.repaint() - if(data == null) return; + if(data == null) return playerNameLabel?.removeAll() @@ -325,10 +325,6 @@ object HiscoresView { return Math.round((base + maxCombatType + summoningFactor) * 1000.0) / 1000.0 } - private fun showError(message: String) { - JOptionPane.showMessageDialog(null, message, "Error", JOptionPane.ERROR_MESSAGE) - } - private fun findComponentByName(container: Container, name: String): Component? { for (component in container.components) { if (name == component.name) { @@ -443,7 +439,7 @@ object HiscoresView { minimumSize = preferredSize } - val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.LVL_BAR_SPRITE)); + val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.LVL_BAR_SPRITE)) val totalLevelIcon = ImageCanvas(bufferedImageSprite).apply { fillColor = COLOR_BACKGROUND_DARK @@ -492,7 +488,7 @@ object HiscoresView { hiscorePanel.add(totalCombatPanel) hiscorePanel.add(Box.createVerticalStrut(10)) - hiScoreView = hiscorePanel; + hiScoreView = hiscorePanel } data class HiscoresResponse( diff --git a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt index 5f1a35a..cfdb4a2 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt @@ -32,15 +32,15 @@ import kotlin.math.ceil object LootTrackerView { private const val SNAPSHOT_LIFESPAN = 10 - const val BAG_ICON = 900; + const val BAG_ICON = 900 val npcDeathSnapshots = mutableMapOf() var gePriceMap = loadGEPrices() - const val VIEW_NAME = "LOOT_TRACKER_VIEW"; + const val VIEW_NAME = "LOOT_TRACKER_VIEW" private val lootItemPanels = mutableMapOf>() private val npcKillCounts = mutableMapOf() private var totalTrackerWidget: XPWidget? = null var lastConfirmedKillNpcId = -1 - var customToolTipWindow: JWindow? = null + private var customToolTipWindow: JWindow? = null var lootTrackerView: JPanel? = null fun loadGEPrices(): Map { @@ -283,7 +283,7 @@ object LootTrackerView { // Function to show the custom tooltip fun showCustomToolTip(location: Point, itemId: Int, quantity: Int, parentComponent: ImageCanvas) { - var itemDef = ObjTypeList.get(itemId) + val itemDef = ObjTypeList.get(itemId) val gePricePerItem = gePriceMap[itemDef.id.toString()]?.toInt() ?: 0 val totalGePrice = gePricePerItem * quantity val totalHaPrice = itemDef.cost * quantity @@ -382,7 +382,7 @@ object LootTrackerView { if (newDrops.isNotEmpty()) { val npcName = NpcTypeList.get(npcId).name - lastConfirmedKillNpcId = npcId; + lastConfirmedKillNpcId = npcId handleNewDrops(npcName.toString(), newDrops, lootTrackerView) toRemove.add(npcId) } else if (snapshot.age >= SNAPSHOT_LIFESPAN) { @@ -501,7 +501,7 @@ object LootTrackerView { return childFramePanel } - fun removeLootFrameMenu(toRemove: JPanel, npcName: String): JPopupMenu { + private fun removeLootFrameMenu(toRemove: JPanel, npcName: String): JPopupMenu { // Create a popup menu val popupMenu = JPopupMenu() val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) @@ -538,7 +538,7 @@ object LootTrackerView { } - fun resetLootTrackerMenu(): JPopupMenu { + private fun resetLootTrackerMenu(): JPopupMenu { // Create a popup menu val popupMenu = JPopupMenu() val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16) diff --git a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt index 60deccf..5b6cfd2 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ReflectiveEditorView.kt @@ -30,7 +30,7 @@ import kotlin.math.ceil object ReflectiveEditorView { var reflectiveEditorView: JPanel? = null - val loadedPlugins: MutableList = mutableListOf() + private val loadedPlugins: MutableList = mutableListOf() const val VIEW_NAME = "REFLECTIVE_EDITOR_VIEW" fun createReflectiveEditorView() { val reflectiveEditorPanel = JPanel(BorderLayout()) @@ -266,7 +266,7 @@ object ReflectiveEditorView { } } else { - loadedPlugins.add(plugin.javaClass.`package`.name); + loadedPlugins.add(plugin.javaClass.`package`.name) } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt b/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt index f955f95..0258838 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt @@ -69,7 +69,7 @@ object SpriteToBufferedImage { * @param brightnessBoost A multiplier to boost the brightness of the image. * @return The BufferedImage created from the sprite. */ - fun convertToBufferedImage( + private fun convertToBufferedImage( sprite: BaseSprite, tint: Color? = null, grayscale: Boolean = false, @@ -88,7 +88,7 @@ object SpriteToBufferedImage { for (y in 0 until height) { for (x in 0 until width) { val index = pixels[y * width + x].toInt() and 0xFF - var color = palette[index] + val color = palette[index] // Apply grayscale or tint if provided val finalColor = if (grayscale) { @@ -109,7 +109,7 @@ object SpriteToBufferedImage { // Manually set pixels directly for (y in 0 until height) { for (x in 0 until width) { - var color = pixels[y * width + x] + val color = pixels[y * width + x] // Apply grayscale or tint if provided val finalColor = if (grayscale) { @@ -137,7 +137,7 @@ object SpriteToBufferedImage { * @param brightnessBoost A multiplier to boost the brightness of the image. * @return The tinted color. */ - fun applyTint(original: Color, tint: Color, brightnessBoost: Float): Color { + private fun applyTint(original: Color, tint: Color, brightnessBoost: Float): Color { val boostedColor = applyBrightness(original, brightnessBoost) val r = (boostedColor.red * tint.red / 255).coerceIn(0, 255) val g = (boostedColor.green * tint.green / 255).coerceIn(0, 255) @@ -152,7 +152,7 @@ object SpriteToBufferedImage { * @param factor The multiplier to boost the brightness. * @return The color with boosted brightness. */ - fun applyBrightness(original: Color, factor: Float): Color { + private fun applyBrightness(original: Color, factor: Float): Color { val r = (original.red * factor).coerceIn(0.0f, 255.0f).toInt() val g = (original.green * factor).coerceIn(0.0f, 255.0f).toInt() val b = (original.blue * factor).coerceIn(0.0f, 255.0f).toInt() @@ -166,7 +166,7 @@ object SpriteToBufferedImage { * @param brightnessBoost A multiplier to boost the brightness. * @return The grayscale version of the color with boosted brightness. */ - fun applyGrayscale(original: Color, brightnessBoost: Float): Color { + private fun applyGrayscale(original: Color, brightnessBoost: Float): Color { // Calculate the grayscale value using the luminosity method val grayValue = (0.3 * original.red + 0.59 * original.green + 0.11 * original.blue).toInt() val boostedGray = (grayValue * brightnessBoost).coerceIn(0.0f, 255.0f).toInt() diff --git a/plugin-playground/src/main/kotlin/KondoKit/XPTable.kt b/plugin-playground/src/main/kotlin/KondoKit/XPTable.kt index 38df208..78138fe 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/XPTable.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/XPTable.kt @@ -6,9 +6,9 @@ import rt4.Node object XPTable { - const val MAX_LEVEL = 99 - const val INVALID_LEVEL = -1 - const val SKILLS_XP_TABLE = 716 + private const val MAX_LEVEL = 99 + private const val INVALID_LEVEL = -1 + private const val SKILLS_XP_TABLE = 716 private var xpTable: MutableList = mutableListOf() diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index fc34967..9eeba19 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -107,7 +107,7 @@ class plugin : Plugin() { private var rightPanelWrapper: JScrollPane? = null private var accumulatedTime = 0L private var reloadInterfaces = false - private const val tickInterval = 600L + private const val TICK_INTERVAL = 600L private var pluginsReloaded = false private var loginScreen = 160 private var lastLogin = "" @@ -126,7 +126,7 @@ class plugin : Plugin() { } } - fun allSpritesLoaded() : Boolean { + private fun allSpritesLoaded() : Boolean { // Check all skill sprites try{ for (i in 0 until 24) { @@ -171,10 +171,10 @@ class plugin : Plugin() { moveAltCanvasToFront() frame.setComponentZOrder(rightPanelWrapper, 2) } - UpdateDisplaySettings() + updateDisplaySettings() } - private fun UpdateDisplaySettings() { + private fun updateDisplaySettings() { val mode = GetWindowMode() val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH lastUIOffset = uiOffset @@ -233,7 +233,7 @@ class plugin : Plugin() { destroyAltCanvas() } if(lastUIOffset != uiOffset){ - UpdateDisplaySettings() + updateDisplaySettings() reloadInterfaces = true } } @@ -242,7 +242,7 @@ class plugin : Plugin() { moveCanvasToFront() frame.remove(altCanvas) altCanvas = null - UpdateDisplaySettings() + updateDisplaySettings() } override fun OnMiniMenuCreate(currentEntries: Array?) { @@ -278,10 +278,10 @@ class plugin : Plugin() { override fun OnPluginsReloaded(): Boolean { if (!initialized) return true - UpdateDisplaySettings() + updateDisplaySettings() frame.remove(rightPanelWrapper) frame.layout = BorderLayout() - frame.add(rightPanelWrapper, BorderLayout.EAST) + rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) } frame.revalidate() pluginsReloaded = true reloadInterfaces = true @@ -332,7 +332,7 @@ class plugin : Plugin() { } accumulatedTime += timeDelta - if (accumulatedTime >= tickInterval) { + if (accumulatedTime >= TICK_INTERVAL) { lootTrackerView?.let { onPostClientTick(it) } accumulatedTime = 0L } @@ -374,21 +374,14 @@ class plugin : Plugin() { } private fun moveAltCanvasToFront(){ - if(altCanvas == null) { - println("WARNING: altcanvas is null") - return - } + if(altCanvas == null) return frame.setComponentZOrder(canvas, 2) frame.setComponentZOrder(altCanvas, 1) frame.setComponentZOrder(rightPanelWrapper, 0) - } private fun moveCanvasToFront(){ - if(altCanvas == null) { - println("WARNING: altcanvas is null") - return - } + if(altCanvas == null) return frame.setComponentZOrder(altCanvas, 2) frame.setComponentZOrder(canvas, 1) frame.setComponentZOrder(rightPanelWrapper, 0) @@ -401,7 +394,7 @@ class plugin : Plugin() { val osName = System.getProperty("os.name").toLowerCase() uiOffset = (GetData("kondoUIOffset") as? Int) ?: if (osName.contains("win")) 16 else 0 launchMinimized = (GetData("kondoLaunchMinimized") as? Boolean) ?: false - useScaledFixed = (GetData("kondoScaleFixed") as? Boolean) ?: false + useScaledFixed = (GetData("kondoScaledFixed") as? Boolean) ?: false } private fun initKondoUI(){ @@ -517,7 +510,7 @@ class plugin : Plugin() { } reloadInterfaces = true - UpdateDisplaySettings() + updateDisplaySettings() // Revalidate and repaint necessary panels mainContentPanel.revalidate() @@ -674,7 +667,7 @@ class plugin : Plugin() { } } - fun loadFont(): Font? { + private fun loadFont(): Font? { val fontStream = plugin::class.java.getResourceAsStream("res/runescape_small.ttf") return if (fontStream != null) { try { @@ -696,7 +689,7 @@ class plugin : Plugin() { var focusedView: String = "" } - fun applyTheme(theme: Theme) { + private fun applyTheme(theme: Theme) { WIDGET_COLOR = theme.widgetColor TITLE_BAR_COLOR = theme.titleBarColor VIEW_BACKGROUND_COLOR = theme.viewBackgroundColor From cb9758f7d5c4d6e4643b8cb738f319545124381a Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 28 Oct 2024 16:22:40 -0700 Subject: [PATCH 43/47] Organize overrides to be together in the source --- .../src/main/kotlin/KondoKit/plugin.kt | 296 +++++++++--------- 1 file changed, 148 insertions(+), 148 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 9eeba19..c0de33a 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -126,24 +126,11 @@ class plugin : Plugin() { } } - private fun allSpritesLoaded() : Boolean { - // Check all skill sprites - try{ - for (i in 0 until 24) { - if(!js5Archive8.isFileReady(getSpriteId(i))){ - return false - } - } - val otherIcons = arrayOf(LVL_ICON, MAG_SPRITE, LOOT_ICON, WRENCH_ICON, COMBAT_LVL_SPRITE, BAG_ICON) - for (icon in otherIcons) { - if(!js5Archive8.isFileReady(icon)){ - return false - } - } - } catch (e : Exception){ - return false - } - return true + override fun Init() { + // Disable Font AA + System.setProperty("sun.java2d.opengl", "false") + System.setProperty("awt.useSystemAAFontSettings", "off") + System.setProperty("swing.aatext", "false") } override fun OnLogin() { @@ -155,96 +142,6 @@ class plugin : Plugin() { lastLogin = Player.usernameInput.toString() } - override fun Init() { - // Disable Font AA - System.setProperty("sun.java2d.opengl", "false") - System.setProperty("awt.useSystemAAFontSettings", "off") - System.setProperty("swing.aatext", "false") - } - - private fun initAltCanvas(){ - if (frame != null) { - altCanvas = AltCanvas().apply { - preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) - } - altCanvas?.let { frame.add(it) } - moveAltCanvasToFront() - frame.setComponentZOrder(rightPanelWrapper, 2) - } - updateDisplaySettings() - } - - private fun updateDisplaySettings() { - val mode = GetWindowMode() - val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH - lastUIOffset = uiOffset - - when (mode) { - WindowMode.FIXED -> { - if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + uiOffset) { - frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + uiOffset, frame.height) - } - - val difference = frame.width - (uiOffset + currentScrollPaneWidth) - - if (useScaledFixed) { - GameShell.leftMargin = 0 - val canvasWidth = difference + uiOffset / 2 - val canvasHeight = frame.height - canvas.y // Restricting height to frame height - - altCanvas?.size = Dimension(canvasWidth, canvasHeight) - altCanvas?.setLocation(0, canvas.y) - canvas.setLocation(0, canvas.y) - } else { - GameShell.leftMargin = (difference + uiOffset) / 2 - canvas.setLocation(GameShell.leftMargin - (FIXED_WIDTH / 2), canvas.y) - } - } - - WindowMode.RESIZABLE -> { - GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + uiOffset) - } - } - - rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) - rightPanelWrapper?.isDoubleBuffered = true - rightPanelWrapper?.revalidate() - rightPanelWrapper?.repaint() - } - - fun OnKondoValueUpdated(){ - StoreData("kondoUseRemoteGE", useLiveGEPrices) - StoreData("kondoTheme", theme.toString()) - if(appliedTheme != theme) { - showAlert( - "KondoKit Theme changes require a relaunch.", - "KondoKit", - JOptionPane.INFORMATION_MESSAGE - ) - } - StoreData("kondoPlayerXPMultiplier", playerXPMultiplier) - LootTrackerView.gePriceMap = LootTrackerView.loadGEPrices() - StoreData("kondoLaunchMinimized", launchMinimized) - StoreData("kondoUIOffset", uiOffset) - StoreData("kondoScaledFixed", useScaledFixed) - if(altCanvas == null && useScaledFixed){ - initAltCanvas() - } else if(altCanvas != null && !useScaledFixed){ - destroyAltCanvas() - } - if(lastUIOffset != uiOffset){ - updateDisplaySettings() - reloadInterfaces = true - } - } - - private fun destroyAltCanvas(){ - moveCanvasToFront() - frame.remove(altCanvas) - altCanvas = null - updateDisplaySettings() - } - override fun OnMiniMenuCreate(currentEntries: Array?) { if (currentEntries != null) { for ((index, entry) in currentEntries.withIndex()) { @@ -265,17 +162,6 @@ class plugin : Plugin() { } } - private fun searchHiscore(username: String): Runnable { - return Runnable { - setActiveView(HiscoresView.VIEW_NAME) - val customSearchField = hiScoreView?.let { HiscoresView.CustomSearchField(it) } - - customSearchField?.searchPlayer(username) ?: run { - println("searchView is null or CustomSearchField creation failed.") - } - } - } - override fun OnPluginsReloaded(): Boolean { if (!initialized) return true updateDisplaySettings() @@ -373,6 +259,149 @@ class plugin : Plugin() { altCanvas?.updateGameImage() // Update the game image as needed } + override fun Update() { + + val widgets = xpWidgets.values + val totalXP = totalXPWidget + + widgets.forEach { xpWidget -> + val elapsedTime = (System.currentTimeMillis() - xpWidget.startTime) / 1000.0 / 60.0 / 60.0 + val xpPerHour = if (elapsedTime > 0) (xpWidget.totalXpGained / elapsedTime).toInt() else 0 + val formattedXpPerHour = formatNumber(xpPerHour) + xpWidget.xpPerHourLabel.text = + formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) + xpWidget.container.repaint() + } + + totalXP?.let { totalXPWidget -> + val elapsedTime = (System.currentTimeMillis() - totalXPWidget.startTime) / 1000.0 / 60.0 / 60.0 + val totalXPPerHour = if (elapsedTime > 0) (totalXPWidget.totalXpGained / elapsedTime).toInt() else 0 + val formattedTotalXpPerHour = formatNumber(totalXPPerHour) + totalXPWidget.xpPerHourLabel.text = + formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) + totalXPWidget.container.repaint() + } + } + + override fun OnKillingBlowNPC(npcID: Int, x: Int, z: Int) { + val preDeathSnapshot = takeGroundSnapshot(Pair(x,z)) + npcDeathSnapshots[npcID] = LootTrackerView.GroundSnapshot(preDeathSnapshot, Pair(x, z), 0) + } + + private fun allSpritesLoaded() : Boolean { + // Check all skill sprites + try{ + for (i in 0 until 24) { + if(!js5Archive8.isFileReady(getSpriteId(i))){ + return false + } + } + val otherIcons = arrayOf(LVL_ICON, MAG_SPRITE, LOOT_ICON, WRENCH_ICON, COMBAT_LVL_SPRITE, BAG_ICON) + for (icon in otherIcons) { + if(!js5Archive8.isFileReady(icon)){ + return false + } + } + } catch (e : Exception){ + return false + } + return true + } + + private fun initAltCanvas(){ + if (frame != null) { + altCanvas = AltCanvas().apply { + preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) + } + altCanvas?.let { frame.add(it) } + moveAltCanvasToFront() + frame.setComponentZOrder(rightPanelWrapper, 2) + } + updateDisplaySettings() + } + + private fun updateDisplaySettings() { + val mode = GetWindowMode() + val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH + lastUIOffset = uiOffset + + when (mode) { + WindowMode.FIXED -> { + if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + uiOffset) { + frame.setSize(FIXED_WIDTH + currentScrollPaneWidth + uiOffset, frame.height) + } + + val difference = frame.width - (uiOffset + currentScrollPaneWidth) + + if (useScaledFixed) { + GameShell.leftMargin = 0 + val canvasWidth = difference + uiOffset / 2 + val canvasHeight = frame.height - canvas.y // Restricting height to frame height + + altCanvas?.size = Dimension(canvasWidth, canvasHeight) + altCanvas?.setLocation(0, canvas.y) + canvas.setLocation(0, canvas.y) + } else { + GameShell.leftMargin = (difference + uiOffset) / 2 + canvas.setLocation(GameShell.leftMargin - (FIXED_WIDTH / 2), canvas.y) + } + } + + WindowMode.RESIZABLE -> { + GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + uiOffset) + } + } + + rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) + rightPanelWrapper?.isDoubleBuffered = true + rightPanelWrapper?.revalidate() + rightPanelWrapper?.repaint() + } + + fun OnKondoValueUpdated(){ + StoreData("kondoUseRemoteGE", useLiveGEPrices) + StoreData("kondoTheme", theme.toString()) + if(appliedTheme != theme) { + showAlert( + "KondoKit Theme changes require a relaunch.", + "KondoKit", + JOptionPane.INFORMATION_MESSAGE + ) + } + StoreData("kondoPlayerXPMultiplier", playerXPMultiplier) + LootTrackerView.gePriceMap = LootTrackerView.loadGEPrices() + StoreData("kondoLaunchMinimized", launchMinimized) + StoreData("kondoUIOffset", uiOffset) + StoreData("kondoScaledFixed", useScaledFixed) + if(altCanvas == null && useScaledFixed){ + initAltCanvas() + } else if(altCanvas != null && !useScaledFixed){ + destroyAltCanvas() + } + if(lastUIOffset != uiOffset){ + updateDisplaySettings() + reloadInterfaces = true + } + } + + private fun destroyAltCanvas(){ + moveCanvasToFront() + frame.remove(altCanvas) + altCanvas = null + updateDisplaySettings() + } + + private fun searchHiscore(username: String): Runnable { + return Runnable { + setActiveView(HiscoresView.VIEW_NAME) + val customSearchField = hiScoreView?.let { HiscoresView.CustomSearchField(it) } + + customSearchField?.searchPlayer(username) ?: run { + println("searchView is null or CustomSearchField creation failed.") + } + } + } + private fun moveAltCanvasToFront(){ if(altCanvas == null) return frame.setComponentZOrder(canvas, 2) @@ -469,35 +498,6 @@ class plugin : Plugin() { } } - override fun Update() { - - val widgets = xpWidgets.values - val totalXP = totalXPWidget - - widgets.forEach { xpWidget -> - val elapsedTime = (System.currentTimeMillis() - xpWidget.startTime) / 1000.0 / 60.0 / 60.0 - val xpPerHour = if (elapsedTime > 0) (xpWidget.totalXpGained / elapsedTime).toInt() else 0 - val formattedXpPerHour = formatNumber(xpPerHour) - xpWidget.xpPerHourLabel.text = - formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) - xpWidget.container.repaint() - } - - totalXP?.let { totalXPWidget -> - val elapsedTime = (System.currentTimeMillis() - totalXPWidget.startTime) / 1000.0 / 60.0 / 60.0 - val totalXPPerHour = if (elapsedTime > 0) (totalXPWidget.totalXpGained / elapsedTime).toInt() else 0 - val formattedTotalXpPerHour = formatNumber(totalXPPerHour) - totalXPWidget.xpPerHourLabel.text = - formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) - totalXPWidget.container.repaint() - } - } - - override fun OnKillingBlowNPC(npcID: Int, x: Int, z: Int) { - val preDeathSnapshot = takeGroundSnapshot(Pair(x,z)) - npcDeathSnapshots[npcID] = LootTrackerView.GroundSnapshot(preDeathSnapshot, Pair(x, z), 0) - } - private fun setActiveView(viewName: String) { // Handle the visibility of the main content panel if (viewName == HIDDEN_VIEW) { From cf5ccbf1acfec6c852146278cb9d0298c19a9776 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 28 Oct 2024 16:32:51 -0700 Subject: [PATCH 44/47] undo some testing changes --- client/src/main/java/plugin/PluginRepository.java | 6 +++--- client/src/main/java/rt4/GameShell.java | 6 ++---- client/src/main/java/rt4/GlRenderer.java | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/src/main/java/plugin/PluginRepository.java b/client/src/main/java/plugin/PluginRepository.java index 4225c8c..55faf80 100644 --- a/client/src/main/java/plugin/PluginRepository.java +++ b/client/src/main/java/plugin/PluginRepository.java @@ -70,7 +70,7 @@ public class PluginRepository { File pluginsDirectory = new File(GlobalJsonConfig.instance.pluginsFolder); if (!pluginsDirectory.exists()) { - //System.out.println("Skipping plugin initialization - " + pluginsDirectory.getAbsolutePath() + " does not exist."); + System.out.println("Skipping plugin initialization - " + pluginsDirectory.getAbsolutePath() + " does not exist."); return; } @@ -120,7 +120,7 @@ public class PluginRepository { } if (loadedPlugins.containsKey(info)) { - //System.out.println("Skipping reloading of plugin " + file.getName() + " as it already exists and has OnPluginsReloaded."); + System.out.println("Skipping reloading of plugin " + file.getName() + " as it already exists and has OnPluginsReloaded."); continue; } @@ -143,7 +143,7 @@ public class PluginRepository { loader.loadClass(file.getName() + "." + f.getName().replace(".class","")); } - //System.out.println("Successfully loaded plugin " + file.getName() + ", version " + info.version); + System.out.println("Successfully loaded plugin " + file.getName() + ", version " + info.version); } } catch (Exception e) { System.err.println("Unexpected exception during plugin initialization:"); diff --git a/client/src/main/java/rt4/GameShell.java b/client/src/main/java/rt4/GameShell.java index 68e6c32..80a799d 100644 --- a/client/src/main/java/rt4/GameShell.java +++ b/client/src/main/java/rt4/GameShell.java @@ -323,7 +323,6 @@ public abstract class GameShell extends Applet implements Runnable, FocusListene @OriginalMember(owner = "client!rc", name = "b", descriptor = "(B)V") public final synchronized void addCanvas() { if (canvas != null) { - // Remove the old canvas if it exists canvas.removeFocusListener(this); canvas.getParent().remove(canvas); } @@ -514,10 +513,9 @@ public abstract class GameShell extends Applet implements Runnable, FocusListene canvasScale = getCurrentDevice().getDefaultConfiguration().getDefaultTransform().getScaleX(); if (frame != null && fullScreenFrame == null) { @Pc(84) Insets insets = frame.getInsets(); - // TODO: Add a flag to ignore this. - //canvas.setLocation(insets.left + leftMargin, topMargin + insets.top); + canvas.setLocation(insets.left + leftMargin, topMargin + insets.top); } else { - //canvas.setLocation(leftMargin, topMargin); + canvas.setLocation(leftMargin, topMargin); } } this.mainRedraw(); diff --git a/client/src/main/java/rt4/GlRenderer.java b/client/src/main/java/rt4/GlRenderer.java index d644740..92e4564 100644 --- a/client/src/main/java/rt4/GlRenderer.java +++ b/client/src/main/java/rt4/GlRenderer.java @@ -73,7 +73,7 @@ public final class GlRenderer { private static int maxTextureCoords; @OriginalMember(owner = "client!tf", name = "E", descriptor = "Lgl!javax/media/opengl/GLDrawable;") - public static GLDrawable drawable; + private static GLDrawable drawable; @OriginalMember(owner = "client!tf", name = "H", descriptor = "Z") public static boolean arbVertexProgramSupported; From e05f5829d7f4654f13f711074242866a797c5b93 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Mon, 28 Oct 2024 16:38:33 -0700 Subject: [PATCH 45/47] Restore original Kondo Fixed mode handling --- plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index c0de33a..f5073ac 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -342,8 +342,8 @@ class plugin : Plugin() { altCanvas?.setLocation(0, canvas.y) canvas.setLocation(0, canvas.y) } else { - GameShell.leftMargin = (difference + uiOffset) / 2 - canvas.setLocation(GameShell.leftMargin - (FIXED_WIDTH / 2), canvas.y) + val difference = frame.width - (FIXED_WIDTH + uiOffset + currentScrollPaneWidth) + GameShell.leftMargin = difference / 2 } } From 3a33995006a50046c423ba0caad8a36ef98fe703 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 3 Nov 2024 10:24:11 -0800 Subject: [PATCH 46/47] Better alt canvas logic --- .../src/main/kotlin/KondoKit/plugin.kt | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index f5073ac..1b57c5a 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -308,23 +308,17 @@ class plugin : Plugin() { return true } - private fun initAltCanvas(){ - if (frame != null) { - altCanvas = AltCanvas().apply { - preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) - } - altCanvas?.let { frame.add(it) } - moveAltCanvasToFront() - frame.setComponentZOrder(rightPanelWrapper, 2) - } - updateDisplaySettings() - } - private fun updateDisplaySettings() { val mode = GetWindowMode() val currentScrollPaneWidth = if (mainContentPanel.isVisible) NAVBAR_WIDTH + MAIN_CONTENT_WIDTH else NAVBAR_WIDTH lastUIOffset = uiOffset + if(mode != WindowMode.FIXED) { + destroyAltCanvas() + } else if (useScaledFixed && altCanvas == null) { + initAltCanvas() + } + when (mode) { WindowMode.FIXED -> { if (frame.width < FIXED_WIDTH + currentScrollPaneWidth + uiOffset) { @@ -373,22 +367,43 @@ class plugin : Plugin() { StoreData("kondoLaunchMinimized", launchMinimized) StoreData("kondoUIOffset", uiOffset) StoreData("kondoScaledFixed", useScaledFixed) - if(altCanvas == null && useScaledFixed){ - initAltCanvas() - } else if(altCanvas != null && !useScaledFixed){ - destroyAltCanvas() - } - if(lastUIOffset != uiOffset){ + if(lastUIOffset != uiOffset || useScaledFixed){ updateDisplaySettings() reloadInterfaces = true } } + private fun initAltCanvas(){ + if(GetWindowMode() != WindowMode.FIXED || altCanvas != null) return + if (frame != null) { + altCanvas = AltCanvas().apply { + preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT) + } + altCanvas?.let { frame.add(it) } + moveAltCanvasToFront() + frame.setComponentZOrder(rightPanelWrapper, 2) + } + } + private fun destroyAltCanvas(){ + if (altCanvas == null) return moveCanvasToFront() frame.remove(altCanvas) altCanvas = null - updateDisplaySettings() + } + + private fun moveAltCanvasToFront(){ + if (altCanvas == null) return + frame.setComponentZOrder(canvas, 2) + frame.setComponentZOrder(altCanvas, 1) + frame.setComponentZOrder(rightPanelWrapper, 0) + } + + private fun moveCanvasToFront(){ + if (altCanvas == null) return + frame.setComponentZOrder(altCanvas, 2) + frame.setComponentZOrder(canvas, 1) + frame.setComponentZOrder(rightPanelWrapper, 0) } private fun searchHiscore(username: String): Runnable { @@ -402,20 +417,6 @@ class plugin : Plugin() { } } - private fun moveAltCanvasToFront(){ - if(altCanvas == null) return - frame.setComponentZOrder(canvas, 2) - frame.setComponentZOrder(altCanvas, 1) - frame.setComponentZOrder(rightPanelWrapper, 0) - } - - private fun moveCanvasToFront(){ - if(altCanvas == null) return - frame.setComponentZOrder(altCanvas, 2) - frame.setComponentZOrder(canvas, 1) - frame.setComponentZOrder(rightPanelWrapper, 0) - } - private fun restoreSettings(){ themeName = (GetData("kondoTheme") as? String) ?: "RUNELITE" useLiveGEPrices = (GetData("kondoUseRemoteGE") as? Boolean) ?: true @@ -490,9 +491,6 @@ class plugin : Plugin() { } else { setActiveView(XPTrackerView.VIEW_NAME) } - if(useScaledFixed) { - initAltCanvas() - } initialized = true pluginsReloaded = true } From 77c5528fc1c4e802047cc28ed1d4eb29ba580436 Mon Sep 17 00:00:00 2001 From: downthecrop Date: Sun, 3 Nov 2024 10:25:50 -0800 Subject: [PATCH 47/47] always update display settings --- plugin-playground/src/main/kotlin/KondoKit/plugin.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index 1b57c5a..fcf4666 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -367,10 +367,10 @@ class plugin : Plugin() { StoreData("kondoLaunchMinimized", launchMinimized) StoreData("kondoUIOffset", uiOffset) StoreData("kondoScaledFixed", useScaledFixed) - if(lastUIOffset != uiOffset || useScaledFixed){ - updateDisplaySettings() + if(lastUIOffset != uiOffset){ reloadInterfaces = true } + updateDisplaySettings() } private fun initAltCanvas(){