diff --git a/client/src/main/java/plugin/Plugin.java b/client/src/main/java/plugin/Plugin.java index e8e3641..7a4a039 100644 --- a/client/src/main/java/plugin/Plugin.java +++ b/client/src/main/java/plugin/Plugin.java @@ -13,7 +13,6 @@ import rt4.Tile; */ public abstract class Plugin { long timeOfLastDraw; - long timeOfLastLateDraw; void _init() { Init(); @@ -25,12 +24,6 @@ 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. @@ -38,14 +31,6 @@ 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 55faf80..2af27f6 100644 --- a/client/src/main/java/plugin/PluginRepository.java +++ b/client/src/main/java/plugin/PluginRepository.java @@ -160,11 +160,6 @@ 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 f641434..5999c44 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") - public int[] pixels; + protected int[] pixels; @OriginalMember(owner = "client!vk", name = "g", descriptor = "Ljava/awt/Image;") protected Image image; diff --git a/client/src/main/java/rt4/GlRenderer.java b/client/src/main/java/rt4/GlRenderer.java index 92e4564..b42e0de 100644 --- a/client/src/main/java/rt4/GlRenderer.java +++ b/client/src/main/java/rt4/GlRenderer.java @@ -9,7 +9,6 @@ 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; @@ -25,11 +24,6 @@ public final class GlRenderer { public static float hFOV = 0; - - private static ByteBuffer pixelByteBuffer; - private static IntBuffer pixelIntBuffer; - public static int[] pixelData; - @OriginalMember(owner = "client!tf", name = "c", descriptor = "F") private static float aFloat30; @@ -206,34 +200,10 @@ public final class GlRenderer { public static void swapBuffers() { try { drawable.swapBuffers(); - readPixels(); } catch (@Pc(3) Exception local3) { } } - 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") public static void setFogEnabled(@OriginalArg(0) boolean enabled) { if (enabled == fogEnabled) { diff --git a/client/src/main/java/rt4/client.java b/client/src/main/java/rt4/client.java index 7a77445..34adc87 100644 --- a/client/src/main/java/rt4/client.java +++ b/client/src/main/java/rt4/client.java @@ -921,7 +921,6 @@ 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/AltCanvas.kt b/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt deleted file mode 100644 index af5c01d..0000000 --- a/plugin-playground/src/main/kotlin/KondoKit/AltCanvas.kt +++ /dev/null @@ -1,166 +0,0 @@ -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 { it.keyPressed(e) } - override fun keyReleased(e: KeyEvent) = relayKeyEvent { it.keyReleased(e) } - override fun keyTyped(e: KeyEvent) = relayKeyEvent { it.keyTyped(e) } - }) - - addMouseWheelListener(MouseWheelListener { e -> relayMouseWheelEvent(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(action: (KeyListener) -> Unit) { - 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() - } - - 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/Helpers.kt b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt index 4f6e3c4..bfcac22 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 && GameShell.canvas.isShowing) { + if (parentComponent != null) { val parentLocation = parentComponent.locationOnScreen val x = parentLocation.x val y = GameShell.canvas.locationOnScreen.y @@ -95,8 +95,10 @@ object Helpers { } - private fun convertToColor(value: String): Color { - return Color.decode(value) + + 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 { @@ -132,7 +134,11 @@ object Helpers { class FieldNotifier(private val plugin: Any) { private val observers = mutableListOf() - private fun notifyFieldChange(field: Field, newValue: Any?) { + fun addObserver(observer: FieldObserver) { + observers.add(observer) + } + + 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 0b48ab3..ecdeed0 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/HiscoresView.kt @@ -7,7 +7,9 @@ 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 @@ -75,8 +77,8 @@ object HiscoresView { private var cursorVisible: Boolean = true private val gson = Gson() - private val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.MAG_SPRITE)) - private val imageCanvas = bufferedImageSprite.let { + val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.MAG_SPRITE)) + val imageCanvas = bufferedImageSprite.let { ImageCanvas(it).apply { preferredSize = Constants.ICON_DIMENSION_SMALL size = preferredSize @@ -110,9 +112,7 @@ object HiscoresView { } else { text += e.keyChar } - SwingUtilities.invokeLater { - repaint() - } + repaint() } override fun keyPressed(e: KeyEvent) { if (e.isControlDown) { @@ -125,9 +125,7 @@ object HiscoresView { val clipboard = Toolkit.getDefaultToolkit().systemClipboard val pasteText = clipboard.getData(DataFlavor.stringFlavor) as String text += pasteText - SwingUtilities.invokeLater { - repaint() - } + repaint() } } } @@ -138,9 +136,7 @@ object HiscoresView { override fun mouseClicked(e: MouseEvent) { if (e.x > width - 20 && e.y < 20) { text = "" - SwingUtilities.invokeLater { - repaint() - } + repaint() } } }) @@ -148,9 +144,7 @@ object HiscoresView { Timer(500) { cursorVisible = !cursorVisible if(focusedView == VIEW_NAME) - SwingUtilities.invokeLater { - repaint() - } + repaint() }.start() } @@ -241,7 +235,7 @@ object HiscoresView { playerNameLabel?.revalidate() playerNameLabel?.repaint() - if(data == null) return + if(data == null) return; playerNameLabel?.removeAll() @@ -325,6 +319,10 @@ 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) { @@ -439,7 +437,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 @@ -488,7 +486,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 cfdb4a2..3a0fc14 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/LootTrackerView.kt @@ -4,6 +4,7 @@ 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 @@ -32,15 +33,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 - private var customToolTipWindow: JWindow? = null + var customToolTipWindow: JWindow? = null var lootTrackerView: JPanel? = null fun loadGEPrices(): Map { @@ -283,7 +284,7 @@ object LootTrackerView { // Function to show the custom tooltip fun showCustomToolTip(location: Point, itemId: Int, quantity: Int, parentComponent: ImageCanvas) { - val itemDef = ObjTypeList.get(itemId) + var itemDef = ObjTypeList.get(itemId) val gePricePerItem = gePriceMap[itemDef.id.toString()]?.toInt() ?: 0 val totalGePrice = gePricePerItem * quantity val totalHaPrice = itemDef.cost * quantity @@ -350,7 +351,6 @@ 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) @@ -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 } - private fun removeLootFrameMenu(toRemove: JPanel, npcName: String): JPopupMenu { + 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 { } - private fun resetLootTrackerMenu(): JPopupMenu { + 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 5b6cfd2..60deccf 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 - private val loadedPlugins: MutableList = mutableListOf() + 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/ScrollablePanel.kt b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt index 0e772b9..cf6444c 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/ScrollablePanel.kt @@ -9,7 +9,6 @@ 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 @@ -84,23 +83,21 @@ class ScrollablePanel(private val content: JPanel) : JPanel() { } private fun handleResize() { - SwingUtilities.invokeLater{ - // Ensure the ScrollablePanel resizes with the frame - 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 lastSize = content.preferredSize.height.coerceAtLeast(frame.height + viewBuffer) content.bounds = Rectangle(0, 0, 242, lastSize) 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) { @@ -109,41 +106,40 @@ class ScrollablePanel(private val content: JPanel) : JPanel() { content.setLocation(0, currentOffsetY) return } - SwingUtilities.invokeLater { - currentOffsetY += deltaY - // Apply buffer to maxOffset - val maxOffset = (frame.height - content.height + viewBuffer).coerceAtMost(0) - currentOffsetY = currentOffsetY.coerceAtMost(0).coerceAtLeast(maxOffset) + currentOffsetY += deltaY - content.setLocation(0, currentOffsetY) + // Apply buffer to maxOffset + val maxOffset = (frame.height - content.height + viewBuffer).coerceAtMost(0) + currentOffsetY = currentOffsetY.coerceAtMost(0).coerceAtLeast(maxOffset) - 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() - } + 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() { - SwingUtilities.invokeLater { - showScrollbar = content.height > frame.height + showScrollbar = content.height > frame.height - val contentHeight = content.height - val viewHeight = frame.height + viewBuffer + 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() + 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/SpriteToBufferedImage.kt b/plugin-playground/src/main/kotlin/KondoKit/SpriteToBufferedImage.kt index 0258838..f955f95 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. */ - private fun convertToBufferedImage( + 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 - val color = palette[index] + var 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) { - val color = pixels[y * width + x] + var 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. */ - private fun applyTint(original: Color, tint: Color, brightnessBoost: Float): Color { + 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. */ - private fun applyBrightness(original: Color, factor: Float): Color { + 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. */ - private fun applyGrayscale(original: Color, brightnessBoost: Float): 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() 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 78138fe..38df208 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 { - private const val MAX_LEVEL = 99 - private const val INVALID_LEVEL = -1 - private const val SKILLS_XP_TABLE = 716 + const val MAX_LEVEL = 99 + const val INVALID_LEVEL = -1 + 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 f5073ac..1fde673 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -34,14 +34,14 @@ import plugin.Plugin import plugin.api.* import plugin.api.API.* import plugin.api.FontColor.fromColor -import rt4.* -import rt4.DisplayMode -import rt4.GameShell.canvas +import rt4.GameShell import rt4.GameShell.frame +import rt4.GlRenderer +import rt4.InterfaceList +import rt4.Player import rt4.client.js5Archive8 import rt4.client.mainLoadState import java.awt.* -import java.awt.Font import java.awt.event.ActionListener import java.awt.event.MouseAdapter import java.awt.event.MouseEvent @@ -91,11 +91,7 @@ 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 useScaledFixed = false - - const val FIXED_WIDTH = 765 - const val FIXED_HEIGHT = 503 + 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 @@ -107,16 +103,14 @@ class plugin : Plugin() { private var rightPanelWrapper: JScrollPane? = null private var accumulatedTime = 0L private var reloadInterfaces = false - private const val TICK_INTERVAL = 600L + private const val tickInterval = 600L private var pluginsReloaded = false private var loginScreen = 160 private var lastLogin = "" 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>() fun registerDrawAction(action: () -> Unit) { @@ -126,11 +120,24 @@ 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") + 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 OnLogin() { @@ -142,6 +149,55 @@ 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 + 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 - (FIXED_WIDTH + uiOffset + currentScrollPaneWidth) + GameShell.leftMargin = difference / 2 + } + WindowMode.RESIZABLE -> { + GameShell.canvasWidth = frame.width - (currentScrollPaneWidth + uiOffset) + } + } + rightPanelWrapper?.preferredSize = Dimension(currentScrollPaneWidth, frame.height) + 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) + if(lastUIOffset != uiOffset){ + UpdateDisplaySettings() + reloadInterfaces = true + } + } + override fun OnMiniMenuCreate(currentEntries: Array?) { if (currentEntries != null) { for ((index, entry) in currentEntries.withIndex()) { @@ -162,43 +218,59 @@ 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() + + UpdateDisplaySettings() + frame.remove(rightPanelWrapper) frame.layout = BorderLayout() - rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) } + 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 - return - } - var xpWidget = xpWidgets[skillId] - if (xpWidget != null) { - updateWidget(xpWidget, xp) - } else { - val previousXp = initialXP[skillId] ?: xp - if (xp == initialXP[skillId]) return + if (!initialXP.containsKey(skillId)) { + initialXP[skillId] = xp + return + } - xpWidget = createXPWidget(skillId, previousXp) - xpWidgets[skillId] = xpWidget + var xpWidget = xpWidgets[skillId] - xpTrackerView?.add(wrappedWidget(xpWidget.container)) - xpTrackerView?.add(Box.createVerticalStrut(5)) + if (xpWidget != null) { + updateWidget(xpWidget, xp) + } else { + val previousXp = initialXP[skillId] ?: xp + if (xp == initialXP[skillId]) return - if(focusedView == XPTrackerView.VIEW_NAME) { - xpTrackerView?.revalidate() - xpTrackerView?.repaint() - } + xpWidget = createXPWidget(skillId, previousXp) + xpWidgets[skillId] = xpWidget - updateWidget(xpWidget, xp) - } + xpTrackerView?.add(wrappedWidget(xpWidget.container)) + xpTrackerView?.add(Box.createVerticalStrut(5)) + + xpTrackerView?.revalidate() + if(focusedView == XPTrackerView.VIEW_NAME) + xpTrackerView?.repaint() + + updateWidget(xpWidget, xp) + } } override fun Draw(timeDelta: Long) { @@ -218,7 +290,7 @@ class plugin : Plugin() { } accumulatedTime += timeDelta - if (accumulatedTime >= TICK_INTERVAL) { + if (accumulatedTime >= tickInterval) { lootTrackerView?.let { onPostClientTick(it) } accumulatedTime = 0L } @@ -240,202 +312,82 @@ 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 first.", - "Error", - JOptionPane.INFORMATION_MESSAGE - ) - return - } - if(!useScaledFixed) return - if(GetWindowMode() == WindowMode.FIXED){ - moveAltCanvasToFront() - } else { - moveCanvasToFront() - } - 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 { - val difference = frame.width - (FIXED_WIDTH + uiOffset + currentScrollPaneWidth) - GameShell.leftMargin = difference / 2 - } - } - - 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) - 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 - 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 - useScaledFixed = (GetData("kondoScaledFixed") 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() - theme = ThemeType.valueOf(themeName) + + loadFont() + val themeIndex = (GetData("kondoTheme") as? String) ?: "RUNELITE" + theme = ThemeType.valueOf(themeIndex) applyTheme(getTheme(theme)) appliedTheme = theme - 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(GameShell.frame) + } 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 cardLayout = CardLayout() mainContentPanel = JPanel(cardLayout).apply { @@ -467,7 +419,7 @@ class plugin : Plugin() { navPanel.add(createNavButton(LOOT_ICON, LootTrackerView.VIEW_NAME)) navPanel.add(createNavButton(WRENCH_ICON, ReflectiveEditorView.VIEW_NAME)) - val rightPanel = Panel(BorderLayout()).apply { + var rightPanel = Panel(BorderLayout()).apply { add(mainContentPanel, BorderLayout.CENTER) add(navPanel, BorderLayout.EAST) } @@ -475,29 +427,53 @@ class plugin : Plugin() { rightPanelWrapper = JScrollPane(rightPanel).apply { preferredSize = Dimension(NAVBAR_WIDTH + MAIN_CONTENT_WIDTH, frame.height) background = VIEW_BACKGROUND_COLOR - border = BorderFactory.createEmptyBorder() + border = BorderFactory.createEmptyBorder() // Removes the border completely horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_NEVER } frame.layout = BorderLayout() - rightPanelWrapper?.let { - frame.add(it, BorderLayout.EAST) - } + rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) } - if(launchMinimized){ - setActiveView(HIDDEN_VIEW) - } else { + if(!launchMinimized){ setActiveView(XPTrackerView.VIEW_NAME) - } - if(useScaledFixed) { - initAltCanvas() + } else { + setActiveView(HIDDEN_VIEW) } initialized = true pluginsReloaded = true } } + 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) { @@ -510,15 +486,14 @@ class plugin : Plugin() { } reloadInterfaces = true - updateDisplaySettings() + UpdateDisplaySettings() // Revalidate and repaint necessary panels mainContentPanel.revalidate() - rightPanelWrapper?.revalidate() - frame?.revalidate() - mainContentPanel.repaint() + rightPanelWrapper?.revalidate() rightPanelWrapper?.repaint() + frame?.revalidate() frame?.repaint() focusedView = viewName @@ -568,7 +543,7 @@ class plugin : Plugin() { maximumSize = buttonSize minimumSize = buttonSize background = WIDGET_COLOR - isOpaque = true + isOpaque = true // Ensure background is painted val gbc = GridBagConstraints().apply { anchor = GridBagConstraints.CENTER @@ -605,69 +580,8 @@ class plugin : Plugin() { return panelButton } - private fun configureLookAndFeel(){ - loadFont() - 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() - } - } - - private fun loadFont(): Font? { + fun loadFont(): Font? { val fontStream = plugin::class.java.getResourceAsStream("res/runescape_small.ttf") return if (fontStream != null) { try { @@ -689,7 +603,7 @@ class plugin : Plugin() { var focusedView: String = "" } - private fun applyTheme(theme: Theme) { + fun applyTheme(theme: Theme) { WIDGET_COLOR = theme.widgetColor TITLE_BAR_COLOR = theme.titleBarColor VIEW_BACKGROUND_COLOR = theme.viewBackgroundColor