Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Proxy Targets #46

Merged
merged 13 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,46 @@ login, which is how third party clients tend to get caught, is unaffected.
This was achieved via numerous clever tricks that will not be explored here,
as to avoid people maliciously using them.

### Private Server Usage
RSProx can currently be used to connect to private servers, but only under
certain circumstances. The following criteria must be met in order to do this:

> [!NOTE]
> This list is subject to changes over time, we hope to improve the overall
> support for further platforms and client types.

1. This only works with Windows and Linux, not macOS.
2. RuneLite is not supported at this time. I will explore this possibility
after revision 229, when gamepacks are private.
3. The client must not have any protocol-breaking changes, same traditional
networking must be used. The only supported change at this time is changing
the varp count in the client from the size-5000 int array.
4. Must be on revision 223 or higher.

#### Setting Up Custom Targets
In order to use the new proxy targets feature, one has to manually fill in the yaml file containing them.
The file is located at `user.home/.rsprox/proxy-targets.yaml`

Here is an example RSPS target:
```yaml
config:
- id: 1
name: Blurite
jav_config_url: "https://client.blurite.io/jav_local_227.ws"
varp_count: 15000
revision: 227.3
modulus: d2a780dccbcf534dc61a36deff725aabf9f46fc9ea298ac8c39b89b5bcb5d0817f8c9f59621187d448da9949aca848d0b2acae50c3122b7da53a79e6fe87ff76b675bcbf5bc18fbd2c9ed8f4cff2b7140508049eb119259af888eb9d20e8cea8a4384b06589483bcda11affd8d67756bc93a4d786494cdf7b634e3228b64116d
```

Properties breakdown:
`id` - A number from 1 to 100, must be unique. This is a required property.
`name` - The name given to the client. Any references to `OldSchool RuneScape` will be replaced by this. This is a required property to ensure caches don't overwrite and cause crashing at runtime when loading different games simultaneously.
`jav_config_url` - The URL to the jav_config that will be used to load initial world and world list. This is a required property.
`varp_count` - Changes the array length used for varps in the client, the default value is 5000. This is an optional property.
`revision` - A revision number used to pick the client and correct decoders. The default is whatever is currently latest stable in Old School RuneScape. This is an optional property.
`modulus` - A hexadecimal (base-16) RSA modulus used to encrypt the login packet sent to the client. This is a required property.


## Progress
Below is a small task list showing a rough breakdown of what the tool will consist of, and how far the progress is at any given moment.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import net.rsprox.gui.AppIcons
import net.rsprox.gui.auth.JagexAuthenticator
import net.rsprox.gui.sessions.SessionType
import net.rsprox.gui.sessions.SessionsPanel
import net.rsprox.proxy.target.ProxyTarget
import net.rsprox.proxy.target.ProxyTargetConfig
import net.rsprox.proxy.util.OperatingSystem
import net.rsprox.shared.account.JagexCharacter
import javax.swing.DefaultComboBoxModel
Expand Down Expand Up @@ -45,7 +47,21 @@ public class LaunchBar(
private val charactersModel = DefaultComboBoxModel<JagexCharacter>()

init {
layout = MigLayout("gap 10", "push[][][]", "[]")
layout = MigLayout("gap 10", "push[][][][]", "[]")
val targetConfigs = App.service.proxyTargets.map(ProxyTarget::config)
val targetConfigsModel = DefaultComboBoxModel(targetConfigs.toTypedArray())
val proxyTargetDropdown =
FlatComboBox<ProxyTargetConfig>().apply {
model = targetConfigsModel
renderer = ProxyTargetCellRenderer()
selectedIndex = App.service.getSelectedProxyTarget()
}
proxyTargetDropdown.addActionListener {
App.service.setSelectedProxyTarget(proxyTargetDropdown.selectedIndex)
}

proxyTargetDropdown.minimumWidth = 160
add(proxyTargetDropdown, "growx")

val characterDropdown = FlatComboBox<JagexCharacter>()
characterDropdown.model = charactersModel
Expand Down Expand Up @@ -181,6 +197,20 @@ public class LaunchBar(
}
}

private class ProxyTargetCellRenderer : DefaultListCellRenderer() {
override fun getListCellRendererComponent(
list: JList<*>?,
value: Any?,
index: Int,
isSelected: Boolean,
cellHasFocus: Boolean,
) = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus).apply {
if (value is ProxyTargetConfig) {
text = value.name
}
}
}

private class JagexCharacterCellRenderer : DefaultListCellRenderer() {
override fun getListCellRendererComponent(
list: JList<*>?,
Expand Down
142 changes: 142 additions & 0 deletions gui/proxy-tool/src/main/kotlin/net/rsprox/gui/dialogs/ErrorDialog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package net.rsprox.gui.dialogs

import com.github.michaelbull.logging.InlineLogger
import net.rsprox.gui.SplashScreen
import java.awt.BorderLayout
import java.awt.Color
import java.awt.Dimension
import java.awt.Font
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import java.awt.image.BufferedImage
import java.io.IOException
import javax.imageio.ImageIO
import javax.swing.*
import javax.swing.border.EmptyBorder

@Suppress("SameParameterValue")
public class ErrorDialog private constructor(
title: String,
message: String,
) : JDialog() {
private val rightColumn = JPanel()
private val font = Font(Font.DIALOG, Font.PLAIN, 12)

init {
try {
SplashScreen::class.java.getResourceAsStream("rsprox_128.png").use { stream ->
setIconImage(ImageIO.read(stream))
}
} catch (e: IOException) {
logger.error(e) {
"Unable to load rsprox 128 image"
}
}
try {
SplashScreen::class.java.getResourceAsStream("rsprox_splash.png").use { stream ->
val logo: BufferedImage = ImageIO.read(stream)
val runelite = JLabel()
runelite.setIcon(ImageIcon(logo))
runelite.setAlignmentX(CENTER_ALIGNMENT)
runelite.setBackground(DARK_GRAY_COLOR)
runelite.setOpaque(true)
rightColumn.add(runelite)
}
} catch (e: IOException) {
logger.error(e) {
"Unable to load rsprox splash image"
}
}
addWindowListener(
object : WindowAdapter() {
override fun windowClosing(e: WindowEvent) {
dispose()
}
},
)
setTitle(title)
layout = BorderLayout()
val pane = contentPane
pane.setBackground(DARKER_GRAY_COLOR)
val leftPane = JPanel()
leftPane.setBackground(DARKER_GRAY_COLOR)
leftPane.setLayout(BorderLayout())
val titleComponent = JLabel("There was an error in RSProx")
titleComponent.setForeground(Color.WHITE)
titleComponent.setFont(font.deriveFont(16f))
titleComponent.setBorder(EmptyBorder(10, 10, 10, 10))
leftPane.add(titleComponent, BorderLayout.NORTH)
leftPane.preferredSize = Dimension(400, 200)
val textArea = JTextArea(message)
textArea.setFont(font)
textArea.setBackground(DARKER_GRAY_COLOR)
textArea.setForeground(Color.LIGHT_GRAY)
textArea.setLineWrap(true)
textArea.setWrapStyleWord(true)
textArea.setBorder(EmptyBorder(10, 10, 10, 10))
textArea.isEditable = false
leftPane.add(textArea, BorderLayout.CENTER)
pane.add(leftPane, BorderLayout.CENTER)
rightColumn.setLayout(BoxLayout(rightColumn, BoxLayout.Y_AXIS))
rightColumn.setBackground(DARK_GRAY_COLOR)
rightColumn.maximumSize = Dimension(200, Int.MAX_VALUE)
pane.add(rightColumn, BorderLayout.EAST)
}

public fun open() {
addButton("Exit") {
dispose()
}
pack()
SplashScreen.stop()
setLocationRelativeTo(null)
isVisible = true
}

private fun addButton(
message: String,
action: Runnable,
): ErrorDialog {
val button = JButton(message)
button.addActionListener { action.run() }
button.setFont(font)
button.setBackground(DARK_GRAY_COLOR)
button.setForeground(Color.LIGHT_GRAY)
button.setBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createMatteBorder(1, 0, 0, 0, DARK_GRAY_COLOR.brighter()),
EmptyBorder(4, 4, 4, 4),
),
)
button.setAlignmentX(CENTER_ALIGNMENT)
button.maximumSize = Dimension(Int.MAX_VALUE, Int.MAX_VALUE)
button.setFocusPainted(false)
button.addChangeListener {
if (button.model.isPressed) {
button.setBackground(DARKER_GRAY_COLOR)
} else if (button.model.isRollover) {
button.setBackground(DARK_GRAY_HOVER_COLOR)
} else {
button.setBackground(DARK_GRAY_COLOR)
}
}
rightColumn.add(button)
rightColumn.revalidate()
return this
}

public companion object {
private val logger = InlineLogger()
private val DARKER_GRAY_COLOR = Color(30, 30, 30)
private val DARK_GRAY_COLOR = Color(40, 40, 40)
private val DARK_GRAY_HOVER_COLOR = Color(35, 35, 35)

public fun show(
title: String,
text: String,
) {
val dialog = ErrorDialog(title, text)
dialog.open()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@ import com.formdev.flatlaf.util.ColorFunctions
import com.github.michaelbull.logging.InlineLogger
import net.rsprox.gui.App
import net.rsprox.gui.AppIcons
import net.rsprox.gui.dialogs.ErrorDialog
import net.rsprox.proxy.binary.BinaryHeader
import net.rsprox.shared.SessionMonitor
import net.rsprox.shared.account.JagexCharacter
import net.rsprox.shared.property.OmitFilteredPropertyTreeFormatter
import net.rsprox.shared.property.Property
import net.rsprox.shared.property.PropertyFormatterCollection
import net.rsprox.shared.property.RootProperty
import net.rsprox.shared.property.isExcluded
import net.rsprox.shared.property.*
import net.rsprox.shared.property.regular.GroupProperty
import net.rsprox.shared.property.regular.ListProperty
import net.rsprox.shared.symbols.SymbolDictionaryProvider
Expand Down Expand Up @@ -184,6 +181,12 @@ public class SessionPanel(
val time =
measureTime {
try {
if (type == SessionType.RuneLite && App.service.getSelectedProxyTarget() != 0) {
return@submit ErrorDialog.show(
"Error launching RuneLite",
"RSProx is unable to launch on a custom target using RuneLite.",
)
}
portNumber = App.service.allocatePort()
when (type) {
SessionType.Java -> TODO()
Expand Down
1 change: 0 additions & 1 deletion proxy/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ dependencies {
implementation(projects.protocol.osrs226)
implementation(projects.protocol.osrs227)
implementation(projects.protocol.osrs228)
implementation(project(mapOf("path" to ":protocol:osrs-228")))
}

tasks.build.configure {
Expand Down
Loading
Loading