greatly reduce flickering

This commit is contained in:
downthecrop 2024-10-26 09:06:23 -07:00
parent 15deb6216f
commit 71afb2b385
4 changed files with 131 additions and 80 deletions

View file

@ -79,12 +79,6 @@ public final class DisplayMode {
@OriginalMember(owner = "client!pm", name = "a", descriptor = "(ZIZIZII)V") @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) { 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) { if (useHD) {
GlRenderer.quit(); GlRenderer.quit();
} }

View file

@ -7,9 +7,7 @@ import KondoKit.Helpers.formatHtmlLabelText
import KondoKit.Helpers.getSpriteId import KondoKit.Helpers.getSpriteId
import KondoKit.Helpers.showToast import KondoKit.Helpers.showToast
import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite
import KondoKit.plugin.Companion.POPUP_BACKGROUND
import KondoKit.plugin.Companion.POPUP_FOREGROUND import KondoKit.plugin.Companion.POPUP_FOREGROUND
import KondoKit.plugin.Companion.TITLE_BAR_COLOR
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR
@ -112,7 +110,9 @@ object HiscoresView {
} else { } else {
text += e.keyChar text += e.keyChar
} }
repaint() SwingUtilities.invokeLater {
repaint()
}
} }
override fun keyPressed(e: KeyEvent) { override fun keyPressed(e: KeyEvent) {
if (e.isControlDown) { if (e.isControlDown) {
@ -125,7 +125,9 @@ object HiscoresView {
val clipboard = Toolkit.getDefaultToolkit().systemClipboard val clipboard = Toolkit.getDefaultToolkit().systemClipboard
val pasteText = clipboard.getData(DataFlavor.stringFlavor) as String val pasteText = clipboard.getData(DataFlavor.stringFlavor) as String
text += pasteText text += pasteText
repaint() SwingUtilities.invokeLater {
repaint()
}
} }
} }
} }
@ -136,7 +138,9 @@ object HiscoresView {
override fun mouseClicked(e: MouseEvent) { override fun mouseClicked(e: MouseEvent) {
if (e.x > width - 20 && e.y < 20) { if (e.x > width - 20 && e.y < 20) {
text = "" text = ""
repaint() SwingUtilities.invokeLater {
repaint()
}
} }
} }
}) })
@ -144,7 +148,9 @@ object HiscoresView {
Timer(500) { Timer(500) {
cursorVisible = !cursorVisible cursorVisible = !cursorVisible
if(focusedView == VIEW_NAME) if(focusedView == VIEW_NAME)
repaint() SwingUtilities.invokeLater {
repaint()
}
}.start() }.start()
} }

View file

@ -9,6 +9,7 @@ import java.awt.Rectangle
import java.awt.event.* import java.awt.event.*
import java.util.* import java.util.*
import javax.swing.JPanel import javax.swing.JPanel
import javax.swing.SwingUtilities
class ScrollablePanel(private val content: JPanel) : JPanel() { class ScrollablePanel(private val content: JPanel) : JPanel() {
private var lastMouseY = 0 private var lastMouseY = 0
@ -80,20 +81,22 @@ class ScrollablePanel(private val content: JPanel) : JPanel() {
} }
private fun handleResize() { private fun handleResize() {
// Ensure the ScrollablePanel resizes with the frame SwingUtilities.invokeLater{
bounds = Rectangle(0, 0, 242, frame.height) // 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 // Dynamically update content bounds and scrollbar on frame resize with buffer
content.bounds = Rectangle(0, 0, 242, content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer)) content.bounds = Rectangle(0, 0, 242, content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer))
showScrollbar = content.height > frame.height showScrollbar = content.height > frame.height
currentOffsetY = 0 currentOffsetY = 0
content.setLocation(0, currentOffsetY) content.setLocation(0, currentOffsetY)
updateScrollbar() updateScrollbar()
revalidate() revalidate()
repaint() repaint()
}
} }
private fun scrollContent(deltaY: Int) { private fun scrollContent(deltaY: Int) {
@ -102,40 +105,41 @@ class ScrollablePanel(private val content: JPanel) : JPanel() {
content.setLocation(0, currentOffsetY) content.setLocation(0, currentOffsetY)
return 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 content.setLocation(0, currentOffsetY)
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 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 val scrollableRatio = viewHeight.toDouble() / contentHeight
scrollbarY = ((-currentOffsetY / contentHeight.toDouble()) * viewHeight).toInt() scrollbarY = ((-currentOffsetY / contentHeight.toDouble()) * viewHeight).toInt()
scrollbarHeight = (viewHeight * scrollableRatio).toInt().coerceAtLeast(20) scrollbarHeight = (viewHeight * scrollableRatio).toInt().coerceAtLeast(20)
} else { repaint()
scrollbarY = 0
scrollbarHeight = 0
} }
}
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) { override fun paintComponent(g: Graphics) {

View file

@ -147,7 +147,8 @@ class plugin : Plugin() {
} }
lastLogin = Player.usernameInput.toString() lastLogin = Player.usernameInput.toString()
} }
class AltCanvas() : JPanel() {
class AltCanvas : Canvas() {
private var gameImage: VolatileImage? = null private var gameImage: VolatileImage? = null
private var scaleX = 1.0 private var scaleX = 1.0
private var scaleY = 1.0 private var scaleY = 1.0
@ -207,15 +208,19 @@ class plugin : Plugin() {
requestFocusInWindow() requestFocusInWindow()
} }
override fun update(g: Graphics) {
paint(g)
}
private fun validateGameImage() { private fun validateGameImage() {
val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration
if (gameImage == null) { if (gameImage == null) {
gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.TRANSLUCENT) gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE)
renderGameImage() renderGameImage()
} else { } else {
val status = gameImage!!.validate(gc) val status = gameImage!!.validate(gc)
if (status == VolatileImage.IMAGE_INCOMPATIBLE) { if (status == VolatileImage.IMAGE_INCOMPATIBLE) {
gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.TRANSLUCENT) gameImage = gc.createCompatibleVolatileImage(765, 503, Transparency.OPAQUE)
renderGameImage() renderGameImage()
} else if (status == VolatileImage.IMAGE_RESTORED) { } else if (status == VolatileImage.IMAGE_RESTORED) {
renderGameImage() renderGameImage()
@ -237,20 +242,35 @@ class plugin : Plugin() {
} }
} }
override fun paintComponent(g: Graphics) { override fun paint(g: Graphics) {
super.paintComponent(g)
val g2d = g as Graphics2D val g2d = g as Graphics2D
// Set the desired background fill color here
g2d.color = Color.BLACK g2d.color = Color.BLACK
g2d.fillRect(0, 0, width, height) 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 -> gameImage?.let { image ->
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
// Scaling and centering
// Calculate aspect-ratio-preserving scale
val imageAspect = image.width.toDouble() / image.height.toDouble() val imageAspect = image.width.toDouble() / image.height.toDouble()
val panelAspect = width.toDouble() / height.toDouble() val panelAspect = width.toDouble() / height.toDouble()
@ -289,7 +309,6 @@ class plugin : Plugin() {
canvas, e.id, e.`when`, e.modifiersEx, canvas, e.id, e.`when`, e.modifiersEx,
originalX, originalY, e.clickCount, e.isPopupTrigger, e.button originalX, originalY, e.clickCount, e.isPopupTrigger, e.button
) )
canvas.dispatchEvent(newEvent) canvas.dispatchEvent(newEvent)
} }
@ -383,8 +402,11 @@ class plugin : Plugin() {
} }
} }
rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height)
rightPanelWrapper?.let { it.isDoubleBuffered = true }
rightPanelWrapper?.revalidate() rightPanelWrapper?.revalidate()
rightPanelWrapper?.repaint() SwingUtilities.invokeLater {
rightPanelWrapper?.repaint()
}
} }
fun OnKondoValueUpdated(){ fun OnKondoValueUpdated(){
@ -446,9 +468,7 @@ class plugin : Plugin() {
frame.remove(rightPanelWrapper) frame.remove(rightPanelWrapper)
frame.layout = BorderLayout() frame.layout = BorderLayout()
frame.add(rightPanelWrapper, BorderLayout.EAST) frame.add(rightPanelWrapper, BorderLayout.EAST)
frame.revalidate() frame.revalidate()
frame.repaint()
pluginsReloaded = true pluginsReloaded = true
reloadInterfaces = true reloadInterfaces = true
return true return true
@ -476,7 +496,9 @@ class plugin : Plugin() {
xpTrackerView?.revalidate() xpTrackerView?.revalidate()
if(focusedView == XPTrackerView.VIEW_NAME) if(focusedView == XPTrackerView.VIEW_NAME)
xpTrackerView?.repaint() SwingUtilities.invokeLater {
xpTrackerView?.repaint()
}
updateWidget(xpWidget, xp) updateWidget(xpWidget, xp)
} }
@ -522,22 +544,35 @@ class plugin : Plugin() {
} }
override fun LateDraw(timeDelta: Long){ override fun LateDraw(timeDelta: Long){
// Clear original canvas for scaled
if(!initialized) return if(!initialized) return
SwingUtilities.invokeLater { SwingUtilities.invokeLater {
var p = Point(-1000,-1000)
if (GetWindowMode() == WindowMode.FIXED) { if (GetWindowMode() == WindowMode.FIXED) {
if (canvas.location != p) { if (canvas.parent !== hiddenFrame?.contentPane) {
println("Moving canvas offscreen"); println("Moving canvas to hidden frame")
canvas.location = p; 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(){ private fun initKondoUI(){
DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2) DrawText(FontType.LARGE, fromColor(Color(16777215)), TextModifier.CENTER, "KondoKit Loading Sprites...", GameShell.canvasWidth/2, GameShell.canvasHeight/2)
if(!allSpritesLoaded()) return; if(!allSpritesLoaded()) return;
@ -683,7 +718,9 @@ class plugin : Plugin() {
val formattedXpPerHour = formatNumber(xpPerHour) val formattedXpPerHour = formatNumber(xpPerHour)
xpWidget.xpPerHourLabel.text = xpWidget.xpPerHourLabel.text =
formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor) formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor)
xpWidget.container.repaint() SwingUtilities.invokeLater{
xpWidget.container.repaint()
}
} }
totalXP?.let { totalXPWidget -> totalXP?.let { totalXPWidget ->
@ -692,7 +729,9 @@ class plugin : Plugin() {
val formattedTotalXpPerHour = formatNumber(totalXPPerHour) val formattedTotalXpPerHour = formatNumber(totalXPPerHour)
totalXPWidget.xpPerHourLabel.text = totalXPWidget.xpPerHourLabel.text =
formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor) 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 // Revalidate and repaint necessary panels
mainContentPanel.revalidate() mainContentPanel.revalidate()
mainContentPanel.repaint()
rightPanelWrapper?.revalidate() rightPanelWrapper?.revalidate()
rightPanelWrapper?.repaint()
frame?.revalidate() frame?.revalidate()
frame?.repaint()
SwingUtilities.invokeLater{
mainContentPanel.repaint()
rightPanelWrapper?.repaint()
frame?.repaint()
}
focusedView = viewName focusedView = viewName
} }
@ -784,15 +826,20 @@ class plugin : Plugin() {
override fun mouseEntered(e: MouseEvent?) { override fun mouseEntered(e: MouseEvent?) {
background = WIDGET_COLOR.darker() background = WIDGET_COLOR.darker()
imageCanvas.fillColor = WIDGET_COLOR.darker() imageCanvas.fillColor = WIDGET_COLOR.darker()
imageCanvas.repaint() SwingUtilities.invokeLater{
repaint() imageCanvas.repaint()
repaint()
}
} }
override fun mouseExited(e: MouseEvent?) { override fun mouseExited(e: MouseEvent?) {
background = WIDGET_COLOR background = WIDGET_COLOR
imageCanvas.fillColor = WIDGET_COLOR imageCanvas.fillColor = WIDGET_COLOR
imageCanvas.repaint() SwingUtilities.invokeLater{
repaint() imageCanvas.repaint()
repaint()
}
} }
override fun mouseClicked(e: MouseEvent?) { override fun mouseClicked(e: MouseEvent?) {