Move some logic from the base plugin to the views as callbacks

This commit is contained in:
downthecrop 2025-09-09 13:24:52 -07:00
parent fec060626b
commit 4a053d5698
7 changed files with 295 additions and 130 deletions

View file

@ -1,40 +1,18 @@
package KondoKit
import KondoKit.Helpers.formatHtmlLabelText
import KondoKit.Helpers.formatNumber
import KondoKit.Helpers.getSpriteId
import KondoKit.Helpers.showAlert
import KondoKit.views.HiscoresView
import KondoKit.views.LootTrackerView
import KondoKit.views.ReflectiveEditorView
import KondoKit.views.*
import KondoKit.views.OnUpdateCallback
import KondoKit.views.OnDrawCallback
import KondoKit.views.OnXPUpdateCallback
import KondoKit.views.OnKillingBlowNPCCallback
import KondoKit.views.OnPostClientTickCallback
import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite
import KondoKit.Themes.Theme
import KondoKit.Themes.ThemeType
import KondoKit.Themes.getTheme
import KondoKit.components.ScrollablePanel
import KondoKit.views.XPTrackerView
import KondoKit.plugin.StateManager.focusedView
import KondoKit.views.Constants.COMBAT_LVL_SPRITE
import KondoKit.views.HiscoresView.createHiscoreSearchView
import KondoKit.views.HiscoresView.hiScoreView
import KondoKit.views.LootTrackerView.BAG_ICON
import KondoKit.views.LootTrackerView.createLootTrackerView
import KondoKit.views.LootTrackerView.lootTrackerView
import KondoKit.views.LootTrackerView.npcDeathSnapshots
import KondoKit.views.LootTrackerView.onPostClientTick
import KondoKit.views.LootTrackerView.takeGroundSnapshot
import KondoKit.views.ReflectiveEditorView.addPlugins
import KondoKit.views.ReflectiveEditorView.createReflectiveEditorView
import KondoKit.views.ReflectiveEditorView.reflectiveEditorView
import KondoKit.views.XPTrackerView.createXPTrackerView
import KondoKit.views.XPTrackerView.createXPWidget
import KondoKit.views.XPTrackerView.initialXP
import KondoKit.views.XPTrackerView.resetXPTracker
import KondoKit.views.XPTrackerView.totalXPWidget
import KondoKit.views.XPTrackerView.updateWidget
import KondoKit.views.XPTrackerView.wrappedWidget
import KondoKit.views.XPTrackerView.xpTrackerView
import KondoKit.views.XPTrackerView.xpWidgets
import plugin.Plugin
import plugin.api.*
import plugin.api.API.*
@ -103,9 +81,9 @@ class plugin : Plugin() {
const val FIXED_HEIGHT = 503
private const val NAVBAR_WIDTH = 30
private const val MAIN_CONTENT_WIDTH = 242
private const val WRENCH_ICON = 907
private const val LOOT_ICON = 777
private const val MAG_SPRITE = 1423
const val WRENCH_ICON = 907
const val LOOT_ICON = 777
const val MAG_SPRITE = 1423
const val LVL_ICON = 898
private lateinit var cardLayout: CardLayout
private lateinit var mainContentPanel: JPanel
@ -123,12 +101,38 @@ class plugin : Plugin() {
private const val HIDDEN_VIEW = "HIDDEN"
private var altCanvas: AltCanvas? = null
private val drawActions = mutableListOf<() -> Unit>()
private val views = mutableListOf<View>()
private val updateCallbacks = mutableListOf<OnUpdateCallback>()
private val drawCallbacks = mutableListOf<OnDrawCallback>()
private val xpUpdateCallbacks = mutableListOf<OnXPUpdateCallback>()
private val killingBlowNPCCallbacks = mutableListOf<OnKillingBlowNPCCallback>()
private val postClientTickCallbacks = mutableListOf<OnPostClientTickCallback>()
fun registerDrawAction(action: () -> Unit) {
synchronized(drawActions) {
drawActions.add(action)
}
}
fun registerUpdateCallback(callback: OnUpdateCallback) {
updateCallbacks.add(callback)
}
fun registerDrawCallback(callback: OnDrawCallback) {
drawCallbacks.add(callback)
}
fun registerXPUpdateCallback(callback: OnXPUpdateCallback) {
xpUpdateCallbacks.add(callback)
}
fun registerKillingBlowNPCCallback(callback: OnKillingBlowNPCCallback) {
killingBlowNPCCallbacks.add(callback)
}
fun registerPostClientTickCallback(callback: OnPostClientTickCallback) {
postClientTickCallbacks.add(callback)
}
}
override fun Init() {
@ -142,7 +146,7 @@ class plugin : Plugin() {
if (lastLogin != "" && lastLogin != Player.usernameInput.toString()) {
// if we logged in with a new character
// we need to reset the trackers
xpTrackerView?.let { resetXPTracker(it) }
XPTrackerView.xpTrackerView?.let { XPTrackerView.resetXPTracker(it) }
}
lastLogin = Player.usernameInput.toString()
}
@ -177,6 +181,9 @@ class plugin : Plugin() {
rightPanelWrapper?.let { frame.add(it, BorderLayout.EAST) }
frame.revalidate()
frame.repaint()
// Rebuild the reflective editor UI on the EDT and in one batch
ReflectiveEditorView.addPlugins(ReflectiveEditorView.panel)
}
pluginsReloaded = true
reloadInterfaces = true
@ -184,52 +191,10 @@ class plugin : Plugin() {
}
override fun OnXPUpdate(skillId: Int, xp: Int) {
if (!initialXP.containsKey(skillId)) {
initialXP[skillId] = xp
return
}
val previousXpSnapshot = initialXP[skillId] ?: xp
if (xp == initialXP[skillId]) return
val ensureOnEdt = Runnable {
var xpWidget = xpWidgets[skillId]
if (xpWidget != null) {
updateWidget(xpWidget, xp)
} else {
xpWidget = createXPWidget(skillId, previousXpSnapshot)
xpWidgets[skillId] = xpWidget
val wrapped = wrappedWidget(xpWidget.container)
// Attach per-widget remove menu
val popupMenu = XPTrackerView.removeXPWidgetMenu(wrapped, skillId)
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)
}
}
Helpers.addMouseListenerToAll(wrapped, rightClickListener)
wrapped.addMouseListener(rightClickListener)
xpTrackerView?.add(wrapped)
xpTrackerView?.add(Box.createVerticalStrut(5))
if(focusedView == XPTrackerView.VIEW_NAME) {
xpTrackerView?.revalidate()
xpTrackerView?.repaint()
}
updateWidget(xpWidget, xp)
}
}
if (SwingUtilities.isEventDispatchThread()) {
ensureOnEdt.run()
} else {
SwingUtilities.invokeLater(ensureOnEdt)
}
// Call registered XP update callbacks
xpUpdateCallbacks.forEach { callback ->
callback.onXPUpdate(skillId, xp)
}
}
override fun Draw(timeDelta: Long) {
@ -241,7 +206,7 @@ class plugin : Plugin() {
if (pluginsReloaded) {
// Rebuild the reflective editor UI on the EDT and in one batch
SwingUtilities.invokeLater {
reflectiveEditorView?.let { addPlugins(it) }
ReflectiveEditorView.addPlugins(ReflectiveEditorView.panel)
}
pluginsReloaded = false
}
@ -253,10 +218,18 @@ class plugin : Plugin() {
accumulatedTime += timeDelta
if (accumulatedTime >= TICK_INTERVAL) {
lootTrackerView?.let { onPostClientTick(it) }
// Call registered post client tick callbacks
postClientTickCallbacks.forEach { callback ->
callback.onPostClientTick()
}
accumulatedTime = 0L
}
// Call registered draw callbacks
drawCallbacks.forEach { callback ->
callback.onDraw(timeDelta)
}
// Draw synced actions (that require to be done between glBegin and glEnd)
if (drawActions.isNotEmpty()) {
synchronized(drawActions) {
@ -294,32 +267,17 @@ 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()
// Call registered update callbacks
updateCallbacks.forEach { callback ->
callback.onUpdate()
}
}
override fun OnKillingBlowNPC(npcID: Int, x: Int, z: Int) {
val preDeathSnapshot = takeGroundSnapshot(Pair(x,z))
npcDeathSnapshots[npcID] = LootTrackerView.GroundSnapshot(preDeathSnapshot, Pair(x, z), 0)
// Call registered killing blow NPC callbacks
killingBlowNPCCallbacks.forEach { callback ->
callback.onKillingBlowNPC(npcID, x, z)
}
}
private fun allSpritesLoaded() : Boolean {
@ -330,7 +288,7 @@ class plugin : Plugin() {
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, Constants.COMBAT_LVL_SPRITE, LootTrackerView.BAG_ICON)
for (icon in otherIcons) {
if(!js5Archive8.isFileReady(icon)){
return false
@ -443,7 +401,7 @@ class plugin : Plugin() {
private fun searchHiscore(username: String): Runnable {
return Runnable {
setActiveView(HiscoresView.VIEW_NAME)
val customSearchField = hiScoreView?.let { HiscoresView.CustomSearchField(it) }
val customSearchField = HiscoresView.hiScoreView?.let { HiscoresView.CustomSearchField(it) }
customSearchField?.searchPlayer(username) ?: run {
println("searchView is null or CustomSearchField creation failed.")
@ -481,15 +439,33 @@ class plugin : Plugin() {
}
// Register Views
createXPTrackerView()
createHiscoreSearchView()
createLootTrackerView()
createReflectiveEditorView()
val xpTrackerView = XPTrackerView
val hiscoresView = HiscoresView
val lootTrackerView = LootTrackerView
val reflectiveEditorView = ReflectiveEditorView
// Create views
xpTrackerView.createView()
hiscoresView.createView()
lootTrackerView.createView()
reflectiveEditorView.createView()
// Register views
views.add(xpTrackerView)
views.add(hiscoresView)
views.add(lootTrackerView)
views.add(reflectiveEditorView)
// Register view functions
xpTrackerView.registerFunctions()
hiscoresView.registerFunctions()
lootTrackerView.registerFunctions()
reflectiveEditorView.registerFunctions()
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)
mainContentPanel.add(ScrollablePanel(xpTrackerView.panel), xpTrackerView.name)
mainContentPanel.add(ScrollablePanel(hiscoresView.panel), hiscoresView.name)
mainContentPanel.add(ScrollablePanel(lootTrackerView.panel), lootTrackerView.name)
mainContentPanel.add(ScrollablePanel(reflectiveEditorView.panel), reflectiveEditorView.name)
val navPanel = Panel().apply {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
@ -497,10 +473,10 @@ class plugin : Plugin() {
preferredSize = Dimension(NAVBAR_WIDTH, frame.height)
}
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))
navPanel.add(createNavButton(xpTrackerView.iconSpriteId, xpTrackerView.name))
navPanel.add(createNavButton(hiscoresView.iconSpriteId, hiscoresView.name))
navPanel.add(createNavButton(lootTrackerView.iconSpriteId, lootTrackerView.name))
navPanel.add(createNavButton(reflectiveEditorView.iconSpriteId, reflectiveEditorView.name))
val rightPanel = Panel(BorderLayout()).apply {
add(mainContentPanel, BorderLayout.CENTER)
@ -515,7 +491,7 @@ class plugin : Plugin() {
verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_NEVER
}
val desiredView = if (launchMinimized) HIDDEN_VIEW else XPTrackerView.VIEW_NAME
val desiredView = if (launchMinimized) HIDDEN_VIEW else xpTrackerView.name
// Commit layout synchronously on the EDT to avoid initial misplacement
val commit = Runnable {
frame.layout = BorderLayout()
@ -580,8 +556,7 @@ class plugin : Plugin() {
} else {
mainContentPanel.repaint()
}
focusedView = viewName
StateManager.focusedView = viewName
}
if (SwingUtilities.isEventDispatchThread()) {
@ -604,7 +579,7 @@ class plugin : Plugin() {
}
lastClickTime = currentTime
if (focusedView == viewName) {
if (StateManager.focusedView == viewName) {
setActiveView("HIDDEN")
} else {
setActiveView(viewName)