mirror of
https://gitlab.com/2009scape/rt4-client.git
synced 2025-12-10 10:20:44 -07:00
Simplify altcanvas
This commit is contained in:
parent
1f1718d917
commit
341d6758c1
1 changed files with 77 additions and 161 deletions
|
|
@ -35,6 +35,7 @@ import plugin.api.*
|
||||||
import plugin.api.API.*
|
import plugin.api.API.*
|
||||||
import plugin.api.FontColor.fromColor
|
import plugin.api.FontColor.fromColor
|
||||||
import rt4.*
|
import rt4.*
|
||||||
|
import rt4.DisplayMode
|
||||||
import rt4.GameShell.canvas
|
import rt4.GameShell.canvas
|
||||||
import rt4.GameShell.frame
|
import rt4.GameShell.frame
|
||||||
import rt4.client.js5Archive8
|
import rt4.client.js5Archive8
|
||||||
|
|
@ -111,6 +112,7 @@ class plugin : Plugin() {
|
||||||
private var lastClickTime = 0L
|
private var lastClickTime = 0L
|
||||||
private var lastUIOffset = 0
|
private var lastUIOffset = 0
|
||||||
private const val HIDDEN_VIEW = "HIDDEN"
|
private const val HIDDEN_VIEW = "HIDDEN"
|
||||||
|
private var altCanvas: AltCanvas? = null
|
||||||
private val drawActions = mutableListOf<() -> Unit>()
|
private val drawActions = mutableListOf<() -> Unit>()
|
||||||
|
|
||||||
fun registerDrawAction(action: () -> Unit) {
|
fun registerDrawAction(action: () -> Unit) {
|
||||||
|
|
@ -151,104 +153,64 @@ class plugin : Plugin() {
|
||||||
|
|
||||||
class AltCanvas : Canvas() {
|
class AltCanvas : Canvas() {
|
||||||
private var gameImage: VolatileImage? = null
|
private var gameImage: VolatileImage? = null
|
||||||
private var flippedPixels: IntArray? = null
|
private var flippedPixels = IntArray(FIXED_WIDTH * FIXED_HEIGHT)
|
||||||
private var bufferImage: BufferedImage? = null
|
private var bufferImage = BufferedImage(FIXED_WIDTH, FIXED_HEIGHT, BufferedImage.TYPE_INT_BGR)
|
||||||
private var scaleX = 1.0
|
private var scaleX = 1.0
|
||||||
private var scaleY = 1.0
|
private var scaleY = 1.0
|
||||||
private var offsetX = 0
|
private var offsetX = 0
|
||||||
private var offsetY = 0
|
private var offsetY = 0
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
validateGameImage()
|
|
||||||
isFocusable = true
|
isFocusable = true
|
||||||
requestFocusInWindow()
|
requestFocusInWindow()
|
||||||
|
|
||||||
addMouseListener(object : MouseAdapter() {
|
addMouseListener(object : MouseAdapter() {
|
||||||
override fun mousePressed(e: MouseEvent) {
|
override fun mousePressed(e: MouseEvent) = relayMouseEvent(e)
|
||||||
relayMouseEvent(e)
|
override fun mouseReleased(e: MouseEvent) = relayMouseEvent(e)
|
||||||
}
|
override fun mouseClicked(e: MouseEvent) = relayMouseEvent(e)
|
||||||
|
|
||||||
override fun mouseReleased(e: MouseEvent) {
|
|
||||||
relayMouseEvent(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mouseClicked(e: MouseEvent) {
|
|
||||||
relayMouseEvent(e)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
addMouseMotionListener(object : MouseMotionAdapter() {
|
addMouseMotionListener(object : MouseMotionAdapter() {
|
||||||
override fun mouseMoved(e: MouseEvent) {
|
override fun mouseMoved(e: MouseEvent) = relayMouseEvent(e)
|
||||||
relayMouseEvent(e)
|
override fun mouseDragged(e: MouseEvent) = relayMouseEvent(e)
|
||||||
}
|
|
||||||
|
|
||||||
override fun mouseDragged(e: MouseEvent) {
|
|
||||||
relayMouseEvent(e)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Register a KeyAdapter for handling key events
|
|
||||||
addKeyListener(object : KeyAdapter() {
|
addKeyListener(object : KeyAdapter() {
|
||||||
override fun keyPressed(e: KeyEvent) {
|
override fun keyPressed(e: KeyEvent) = relayKeyEvent(e) { it.keyPressed(e) }
|
||||||
for (listener in canvas.keyListeners) {
|
override fun keyReleased(e: KeyEvent) = relayKeyEvent(e) { it.keyReleased(e) }
|
||||||
listener.keyPressed(e)
|
override fun keyTyped(e: KeyEvent) = relayKeyEvent(e) { it.keyTyped(e) }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun keyReleased(e: KeyEvent) {
|
|
||||||
for (listener in canvas.keyListeners) {
|
|
||||||
listener.keyReleased(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun keyTyped(e: KeyEvent) {
|
|
||||||
for (listener in canvas.keyListeners) {
|
|
||||||
listener.keyTyped(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
isFocusable = true
|
|
||||||
requestFocusInWindow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update(g: Graphics) {
|
override fun update(g: Graphics) = paint(g)
|
||||||
paint(g)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addNotify() {
|
override fun addNotify() {
|
||||||
super.addNotify()
|
super.addNotify()
|
||||||
//createBufferStrategy(2) // Double buffering for V-Sync, called only after the peer is created
|
validateGameImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateGameImage() {
|
private fun validateGameImage() {
|
||||||
val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration
|
val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration
|
||||||
if (gameImage == null) {
|
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)
|
gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE)
|
||||||
renderGameImage()
|
renderGameImage()
|
||||||
} else {
|
|
||||||
val status = gameImage!!.validate(gc)
|
|
||||||
if (status == VolatileImage.IMAGE_INCOMPATIBLE) {
|
|
||||||
gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE)
|
|
||||||
renderGameImage()
|
|
||||||
} else if (status == VolatileImage.IMAGE_RESTORED) {
|
|
||||||
renderGameImage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderGameImage() {
|
private fun renderGameImage() {
|
||||||
val g = gameImage!!.createGraphics()
|
gameImage?.createGraphics()?.apply {
|
||||||
try {
|
color = Color.RED
|
||||||
// Initial drawing code
|
fillRect(0, 0, gameImage!!.width, gameImage!!.height)
|
||||||
g.color = Color.RED
|
color = Color.BLACK
|
||||||
g.fillRect(0, 0, gameImage!!.width, gameImage!!.height)
|
drawString("Game Frame", 20, 20)
|
||||||
g.color = Color.BLACK
|
dispose()
|
||||||
g.drawString("Game Frame", 20, 20)
|
|
||||||
// Add any additional rendering here
|
|
||||||
} finally {
|
|
||||||
g.dispose()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,104 +219,58 @@ class plugin : Plugin() {
|
||||||
g2d.color = Color.BLACK
|
g2d.color = Color.BLACK
|
||||||
g2d.fillRect(0, 0, width, height)
|
g2d.fillRect(0, 0, width, height)
|
||||||
|
|
||||||
// Validate image within paint to ensure compatibility with GraphicsConfiguration
|
|
||||||
var valid = false
|
|
||||||
do {
|
|
||||||
val gc = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice.defaultConfiguration
|
|
||||||
if (gameImage == null) {
|
|
||||||
gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE)
|
|
||||||
renderGameImage()
|
|
||||||
} else {
|
|
||||||
val status = gameImage!!.validate(gc)
|
|
||||||
when (status) {
|
|
||||||
VolatileImage.IMAGE_INCOMPATIBLE -> {
|
|
||||||
gameImage = gc.createCompatibleVolatileImage(FIXED_WIDTH, FIXED_HEIGHT, Transparency.OPAQUE)
|
|
||||||
renderGameImage()
|
|
||||||
}
|
|
||||||
VolatileImage.IMAGE_RESTORED -> renderGameImage()
|
|
||||||
VolatileImage.IMAGE_OK -> valid = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (!valid)
|
|
||||||
|
|
||||||
// Continue with rendering the image
|
|
||||||
gameImage?.let { image ->
|
gameImage?.let { image ->
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
|
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
|
||||||
// Scaling and centering
|
val (drawWidth, drawHeight) = calculateDrawDimensions(image)
|
||||||
val imageAspect = image.width.toDouble() / image.height.toDouble()
|
|
||||||
val panelAspect = width.toDouble() / height.toDouble()
|
|
||||||
|
|
||||||
val (drawWidth, drawHeight) = if (imageAspect > panelAspect) {
|
|
||||||
val newWidth = width
|
|
||||||
val newHeight = (width / imageAspect).toInt()
|
|
||||||
newWidth to newHeight
|
|
||||||
} else {
|
|
||||||
val newHeight = height
|
|
||||||
val newWidth = (height * imageAspect).toInt()
|
|
||||||
newWidth to newHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store scale factors and offsets for event adjustment
|
|
||||||
scaleX = drawWidth.toDouble() / image.width
|
scaleX = drawWidth.toDouble() / image.width
|
||||||
scaleY = drawHeight.toDouble() / image.height
|
scaleY = drawHeight.toDouble() / image.height
|
||||||
offsetX = (width - drawWidth) / 2
|
offsetX = (width - drawWidth) / 2
|
||||||
offsetY = (height - drawHeight) / 2
|
offsetY = (height - drawHeight) / 2
|
||||||
|
g2d.drawImage(image, offsetX, offsetY, drawWidth, drawHeight, null)
|
||||||
|
Toolkit.getDefaultToolkit().sync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Draw the scaled image centered in the panel
|
private fun calculateDrawDimensions(image: VolatileImage): Pair<Int, Int> {
|
||||||
val x = offsetX
|
val imageAspect = image.width.toDouble() / image.height.toDouble()
|
||||||
val y = offsetY
|
val panelAspect = width.toDouble() / height.toDouble()
|
||||||
g2d.drawImage(image, x, y, drawWidth, drawHeight, null)
|
return if (imageAspect > panelAspect) {
|
||||||
g2d.dispose()
|
width to (width / imageAspect).toInt()
|
||||||
//bufferStrategy.show() // Shows the buffer with V-Sync enabled
|
} else {
|
||||||
Toolkit.getDefaultToolkit().sync() // Ensures V-Sync on some systems
|
(height * imageAspect).toInt() to height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun relayMouseEvent(e: MouseEvent) {
|
private fun relayMouseEvent(e: MouseEvent) {
|
||||||
this.requestFocusInWindow()
|
requestFocusInWindow()
|
||||||
val adjustedX = (e.x - offsetX) / scaleX
|
val adjustedX = ((e.x - offsetX) / scaleX).toInt().coerceIn(0, gameImage!!.width - 1)
|
||||||
val adjustedY = (e.y - offsetY) / scaleY
|
val adjustedY = ((e.y - offsetY) / scaleY).toInt().coerceIn(0, gameImage!!.height - 1)
|
||||||
|
canvas.dispatchEvent(MouseEvent(canvas, e.id, e.`when`, e.modifiersEx, adjustedX, adjustedY, e.clickCount, e.isPopupTrigger, e.button))
|
||||||
|
}
|
||||||
|
|
||||||
val originalX = adjustedX.toInt().coerceIn(0, gameImage!!.width - 1)
|
private fun relayKeyEvent(e: KeyEvent, action: (KeyListener) -> Unit) {
|
||||||
val originalY = adjustedY.toInt().coerceIn(0, gameImage!!.height - 1)
|
for (listener in canvas.keyListeners) action(listener)
|
||||||
|
|
||||||
val newEvent = MouseEvent(
|
|
||||||
canvas, e.id, e.`when`, e.modifiersEx,
|
|
||||||
originalX, originalY, e.clickCount, e.isPopupTrigger, e.button
|
|
||||||
)
|
|
||||||
canvas.dispatchEvent(newEvent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateGameImage() {
|
fun updateGameImage() {
|
||||||
if(this.parent == null) {
|
if (IsHD()) renderGlRaster() else renderSoftwareRaster()
|
||||||
println("Unparented.. skipping update.")
|
|
||||||
}
|
|
||||||
validateGameImage()
|
|
||||||
if (IsHD()) {
|
|
||||||
renderGlRaster()
|
|
||||||
} else {
|
|
||||||
renderSoftwareRaster()
|
|
||||||
}
|
|
||||||
repaint()
|
repaint()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderGlRaster() {
|
private fun renderGlRaster() {
|
||||||
if (flippedPixels == null || flippedPixels!!.size != gameImage!!.width * gameImage!!.height) {
|
|
||||||
flippedPixels = IntArray(gameImage!!.width * gameImage!!.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize bufferImage only once and reuse it
|
|
||||||
if (bufferImage == null || bufferImage!!.width != gameImage!!.width || bufferImage!!.height != gameImage!!.height) {
|
|
||||||
bufferImage = BufferedImage(gameImage!!.width, gameImage!!.height, BufferedImage.TYPE_INT_BGR)
|
|
||||||
}
|
|
||||||
|
|
||||||
val width = gameImage!!.width
|
val width = gameImage!!.width
|
||||||
val height = gameImage!!.height
|
val height = gameImage!!.height
|
||||||
val pixels = GlRenderer.pixelData // Retrieve BGRA pixel data
|
val pixelData = GlRenderer.pixelData
|
||||||
|
|
||||||
|
// Flip and copy pixels in one pass using a single loop
|
||||||
for (y in 0 until height) {
|
for (y in 0 until height) {
|
||||||
System.arraycopy(pixels, (height - 1 - y) * width, flippedPixels, y * width, width)
|
val srcOffset = (height - 1 - y) * width
|
||||||
|
val destOffset = y * width
|
||||||
|
System.arraycopy(pixelData, srcOffset, flippedPixels, destOffset, width)
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferImage!!.setRGB(0, 0, width, height, flippedPixels, 0, width)
|
// Draw flipped pixels directly to bufferImage
|
||||||
|
bufferImage.setRGB(0, 0, width, height, flippedPixels, 0, width)
|
||||||
|
|
||||||
gameImage?.createGraphics()?.apply {
|
gameImage?.createGraphics()?.apply {
|
||||||
drawImage(bufferImage, 0, 0, null)
|
drawImage(bufferImage, 0, 0, null)
|
||||||
|
|
@ -363,23 +279,19 @@ class plugin : Plugin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderSoftwareRaster() {
|
private fun renderSoftwareRaster() {
|
||||||
val g = gameImage!!.createGraphics()
|
gameImage?.createGraphics()?.apply {
|
||||||
try {
|
SoftwareRaster.frameBuffer.draw(this)
|
||||||
SoftwareRaster.frameBuffer.draw(g)
|
dispose()
|
||||||
} finally {
|
|
||||||
g.dispose()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createAltCanvas(): AltCanvas {
|
private fun createAltCanvas(): AltCanvas {
|
||||||
return AltCanvas().apply {
|
return AltCanvas().apply {
|
||||||
preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT)
|
preferredSize = Dimension(FIXED_WIDTH, FIXED_HEIGHT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var altCanvas: AltCanvas? = null
|
|
||||||
|
|
||||||
|
|
||||||
override fun Init() {
|
override fun Init() {
|
||||||
// Disable Font AA
|
// Disable Font AA
|
||||||
|
|
@ -552,6 +464,14 @@ class plugin : Plugin() {
|
||||||
|
|
||||||
override fun LateDraw(timeDelta: Long) {
|
override fun LateDraw(timeDelta: Long) {
|
||||||
if (!initialized) return
|
if (!initialized) return
|
||||||
|
if(GameShell.fullScreenFrame != null) {
|
||||||
|
DisplayMode.setWindowMode(true, 0, FIXED_WIDTH, FIXED_HEIGHT)
|
||||||
|
showAlert("Fullscreen is not supported by KondoKit. Disable the plugin",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.INFORMATION_MESSAGE
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(GetWindowMode() == WindowMode.RESIZABLE){
|
if(GetWindowMode() == WindowMode.RESIZABLE){
|
||||||
frame.setComponentZOrder(altCanvas, 1)
|
frame.setComponentZOrder(altCanvas, 1)
|
||||||
frame.setComponentZOrder(canvas, 0)
|
frame.setComponentZOrder(canvas, 0)
|
||||||
|
|
@ -708,24 +628,20 @@ class plugin : Plugin() {
|
||||||
val elapsedTime = (System.currentTimeMillis() - xpWidget.startTime) / 1000.0 / 60.0 / 60.0
|
val elapsedTime = (System.currentTimeMillis() - xpWidget.startTime) / 1000.0 / 60.0 / 60.0
|
||||||
val xpPerHour = if (elapsedTime > 0) (xpWidget.totalXpGained / elapsedTime).toInt() else 0
|
val xpPerHour = if (elapsedTime > 0) (xpWidget.totalXpGained / elapsedTime).toInt() else 0
|
||||||
val formattedXpPerHour = formatNumber(xpPerHour)
|
val formattedXpPerHour = formatNumber(xpPerHour)
|
||||||
SwingUtilities.invokeLater{
|
|
||||||
xpWidget.xpPerHourLabel.text =
|
xpWidget.xpPerHourLabel.text =
|
||||||
formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor)
|
formatHtmlLabelText("XP /hr: ", primaryColor, formattedXpPerHour, secondaryColor)
|
||||||
xpWidget.container.repaint()
|
xpWidget.container.repaint()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
totalXP?.let { totalXPWidget ->
|
totalXP?.let { totalXPWidget ->
|
||||||
val elapsedTime = (System.currentTimeMillis() - totalXPWidget.startTime) / 1000.0 / 60.0 / 60.0
|
val elapsedTime = (System.currentTimeMillis() - totalXPWidget.startTime) / 1000.0 / 60.0 / 60.0
|
||||||
val totalXPPerHour = if (elapsedTime > 0) (totalXPWidget.totalXpGained / elapsedTime).toInt() else 0
|
val totalXPPerHour = if (elapsedTime > 0) (totalXPWidget.totalXpGained / elapsedTime).toInt() else 0
|
||||||
val formattedTotalXpPerHour = formatNumber(totalXPPerHour)
|
val formattedTotalXpPerHour = formatNumber(totalXPPerHour)
|
||||||
SwingUtilities.invokeLater{
|
|
||||||
totalXPWidget.xpPerHourLabel.text =
|
totalXPWidget.xpPerHourLabel.text =
|
||||||
formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor)
|
formatHtmlLabelText("XP /hr: ", primaryColor, formattedTotalXpPerHour, secondaryColor)
|
||||||
totalXPWidget.container.repaint()
|
totalXPWidget.container.repaint()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun OnKillingBlowNPC(npcID: Int, x: Int, z: Int) {
|
override fun OnKillingBlowNPC(npcID: Int, x: Int, z: Int) {
|
||||||
val preDeathSnapshot = takeGroundSnapshot(Pair(x,z))
|
val preDeathSnapshot = takeGroundSnapshot(Pair(x,z))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue