Kondo 2.0

This commit is contained in:
downthecrop 2024-10-08 01:20:42 -07:00
parent 637e5bf68a
commit b8c7a1150f
14 changed files with 1265 additions and 474 deletions

View file

@ -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<out MiniMenuEntry>?) {
@ -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("<col=[0-9a-fA-F]{6}>"), "")
.replace(Regex("<img=\\d+>"), "")
.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("<col=[0-9a-fA-F]{6}>"), "") // Remove color tags
.replace(Regex("<img=\\d+>"), "") // 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<Int, Int> = HashMap()
val xpWidgets: MutableMap<Int, XPWidget> = HashMap()
var totalXPWidget: XPWidget? = null
var focusedView: String = ""
}
}