Initial push
0
.idea/.gitignore
generated
vendored
Normal file
22
build.gradle
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '1.4.32'
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'org.rs09'
|
||||||
|
version '1.0'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
||||||
|
implementation 'org.jsoup:jsoup:1.14.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'Main-Class': 'MainWindow'
|
||||||
|
}
|
||||||
|
from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
|
||||||
|
}
|
||||||
1
gradle.properties
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
kotlin.code.style=official
|
||||||
2
settings.gradle
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
rootProject.name = 'rs09launcher'
|
||||||
|
|
||||||
15
src/main/kotlin/BackgroundLabel.kt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import java.awt.BorderLayout
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.GridBagLayout
|
||||||
|
import javax.swing.JLabel
|
||||||
|
|
||||||
|
class BackgroundLabel(url: String, text: String) : BackgroundPanel(url) {
|
||||||
|
val textLabel = JLabel("<html><div style='text-align: center;'>$text</div></html")
|
||||||
|
|
||||||
|
init {
|
||||||
|
isVisible = false
|
||||||
|
layout = GridBagLayout()
|
||||||
|
textLabel.foreground = Color(255,255,255)
|
||||||
|
add(textLabel)
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/main/kotlin/BackgroundPanel.kt
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import java.awt.Dimension
|
||||||
|
import java.awt.Graphics
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
import javax.swing.JPanel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Won't lie, I stole this from some nice person on StackOverflow so I didn't have to figure it out myself.
|
||||||
|
* Credit: https://stackoverflow.com/questions/24746354/java-jpanel-tiled-background-image
|
||||||
|
*/
|
||||||
|
open class BackgroundPanel(var tileImage: BufferedImage?, url: String = "") : JPanel() {
|
||||||
|
constructor(url: String) : this(null, url)
|
||||||
|
|
||||||
|
init {
|
||||||
|
if(url.isNotBlank()) tileImage = ImageIO.read(javaClass.getResource(url))
|
||||||
|
layout = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun paintComponent(g: Graphics) {
|
||||||
|
val width = width
|
||||||
|
val height = height
|
||||||
|
run {
|
||||||
|
var x = 0
|
||||||
|
while (x < width) {
|
||||||
|
run {
|
||||||
|
var y = 0
|
||||||
|
while (y < height) {
|
||||||
|
g.drawImage(tileImage, x, y, this)
|
||||||
|
y += tileImage!!.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x += tileImage!!.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPreferredSize(): Dimension {
|
||||||
|
return Dimension(240, 240)
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/main/kotlin/Checksum.kt
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.net.URL
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.security.NoSuchAlgorithmException
|
||||||
|
import kotlin.experimental.and
|
||||||
|
|
||||||
|
object Checksum {
|
||||||
|
val localChecksum: String?
|
||||||
|
get() {
|
||||||
|
val local: File = File(Settings.SAVE_DIR + Settings.SAVE_NAME)
|
||||||
|
try {
|
||||||
|
FileInputStream(local).use { fis -> return calculateMd5(fis) }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
MainWindow.loadingLabel.text = e.message
|
||||||
|
MainWindow.loadingLabel.repaint()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLocalChecksum(file: String?): String {
|
||||||
|
val local = File(file!!)
|
||||||
|
if(!local.exists()) return ""
|
||||||
|
else FileInputStream(local).use { fis -> return calculateMd5(fis) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val remoteChecksum: String?
|
||||||
|
get() {
|
||||||
|
try {
|
||||||
|
URL(Settings.DOWNLOAD_URL).openStream().use { stream -> return calculateMd5(stream) }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
MainWindow.loadingLabel.text = e.message
|
||||||
|
MainWindow.loadingLabel.repaint()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRemoteChecksum(url: String?): String? {
|
||||||
|
try {
|
||||||
|
URL(url).openStream().use { stream -> return calculateMd5(stream) }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
MainWindow.loadingLabel.text = e.message
|
||||||
|
MainWindow.loadingLabel.repaint()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calculateMd5(instream: InputStream): String {
|
||||||
|
return calculateDigest(instream, "MD5")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateDigest(instream: InputStream, algorithm: String): String {
|
||||||
|
val buffer = ByteArray(4096)
|
||||||
|
val messageDigest = getMessageDigest(algorithm)
|
||||||
|
messageDigest!!.reset()
|
||||||
|
var bytesRead: Int
|
||||||
|
try {
|
||||||
|
while (instream.read(buffer).also { bytesRead = it } != -1) {
|
||||||
|
messageDigest.update(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
System.err.println("Error making a '$algorithm' digest on the inputstream")
|
||||||
|
}
|
||||||
|
return toHex(messageDigest.digest())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toHex(ba: ByteArray): String {
|
||||||
|
val baLen = ba.size
|
||||||
|
val hexchars = CharArray(baLen * 2)
|
||||||
|
var cIdx = 0
|
||||||
|
for (i in 0 until baLen) {
|
||||||
|
hexchars[cIdx++] = hexdigit[(ba[i].toInt() shr 4) and 0x0F]
|
||||||
|
hexchars[cIdx++] = hexdigit[(ba[i] and 0x0F).toInt()]
|
||||||
|
}
|
||||||
|
return String(hexchars)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMessageDigest(algorithm: String): MessageDigest? {
|
||||||
|
var messageDigest: MessageDigest? = null
|
||||||
|
try {
|
||||||
|
messageDigest = MessageDigest.getInstance(algorithm)
|
||||||
|
} catch (e: NoSuchAlgorithmException) {
|
||||||
|
System.err.println("The '$algorithm' algorithm is not available")
|
||||||
|
}
|
||||||
|
return messageDigest
|
||||||
|
}
|
||||||
|
|
||||||
|
private val hexdigit = charArrayOf(
|
||||||
|
'0', '1', '2', '3', '4', '5',
|
||||||
|
'6', '7', '8', '9', 'a', 'b',
|
||||||
|
'c', 'd', 'e', 'f'
|
||||||
|
)
|
||||||
|
}
|
||||||
6
src/main/kotlin/Extensions.kt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import java.awt.Component
|
||||||
|
|
||||||
|
fun Component.placeAt(x: Int, y: Int, width: Int, height: Int){
|
||||||
|
this.setBounds(x,y,width,height)
|
||||||
|
if(this is ImgButton) this.scale(width,height)
|
||||||
|
}
|
||||||
55
src/main/kotlin/ImgButton.kt
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import java.awt.Image
|
||||||
|
import java.awt.event.MouseEvent
|
||||||
|
import java.awt.event.MouseListener
|
||||||
|
import javax.swing.Icon
|
||||||
|
import javax.swing.ImageIcon
|
||||||
|
import javax.swing.JLabel
|
||||||
|
|
||||||
|
class ImgButton(enabledURL: String, disabledURL: String = enabledURL, val autoHandleMouse: Boolean = true) : JLabel() {
|
||||||
|
|
||||||
|
private var hoverMethod: (MouseEvent) -> Unit = {}
|
||||||
|
private var mouseLeaveMethod: (MouseEvent) -> Unit = {}
|
||||||
|
private var onClickMethod: (MouseEvent) -> Unit = {}
|
||||||
|
|
||||||
|
init {
|
||||||
|
isEnabled = false
|
||||||
|
icon = ImageIcon(javaClass.getResource(enabledURL))
|
||||||
|
disabledIcon = ImageIcon(javaClass.getResource(disabledURL))
|
||||||
|
addMouseListener(object : MouseListener {
|
||||||
|
override fun mouseClicked(p0: MouseEvent) {
|
||||||
|
onClickMethod.invoke(p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mousePressed(p0: MouseEvent?) {}
|
||||||
|
|
||||||
|
override fun mouseReleased(p0: MouseEvent?) {}
|
||||||
|
|
||||||
|
override fun mouseEntered(p0: MouseEvent) {
|
||||||
|
if(autoHandleMouse) isEnabled = true
|
||||||
|
hoverMethod.invoke(p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseExited(p0: MouseEvent) {
|
||||||
|
if(autoHandleMouse) isEnabled = false
|
||||||
|
mouseLeaveMethod.invoke(p0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onClick(handler: (event: MouseEvent) -> Unit){
|
||||||
|
onClickMethod = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMouseEnter(handler: (event: MouseEvent) -> Unit){
|
||||||
|
hoverMethod = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMouseExit(handler: (event: MouseEvent) -> Unit){
|
||||||
|
mouseLeaveMethod = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
fun scale(width: Int, height: Int){
|
||||||
|
icon = ImageIcon((icon as ImageIcon).image.getScaledInstance(width,height, Image.SCALE_SMOOTH))
|
||||||
|
disabledIcon = ImageIcon((disabledIcon as ImageIcon).image.getScaledInstance(width, height, Image.SCALE_SMOOTH))
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/main/kotlin/LatestUpdatePane.kt
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import org.jsoup.nodes.Node
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Dimension
|
||||||
|
import java.awt.Graphics
|
||||||
|
import java.awt.Rectangle
|
||||||
|
import javax.swing.JButton
|
||||||
|
import javax.swing.JComponent
|
||||||
|
import javax.swing.JScrollPane
|
||||||
|
import javax.swing.JTextPane
|
||||||
|
import javax.swing.plaf.basic.BasicScrollBarUI
|
||||||
|
|
||||||
|
class LatestUpdatePane(url: String) : JScrollPane() {
|
||||||
|
val texPane = JTextPane()
|
||||||
|
init {
|
||||||
|
texPane.contentType = "text/html"
|
||||||
|
|
||||||
|
texPane.putClientProperty(JTextPane.HONOR_DISPLAY_PROPERTIES, true)
|
||||||
|
border = null
|
||||||
|
|
||||||
|
val doc = Jsoup.connect(url).get()
|
||||||
|
doc.getElementsByTag("img").remove()
|
||||||
|
removeComments(doc)
|
||||||
|
val postBody = doc.select(".rightpanel").select(".msgcontents")
|
||||||
|
texPane.text = postBody.toString()
|
||||||
|
setViewportView(texPane)
|
||||||
|
|
||||||
|
getViewport().background = Color(153,132,104)
|
||||||
|
texPane.background = Color(153,132,104)
|
||||||
|
background = Color(153,132,104)
|
||||||
|
|
||||||
|
getVerticalScrollBar().ui = object : BasicScrollBarUI() {
|
||||||
|
override fun configureScrollBarColors() {
|
||||||
|
this.thumbColor = Color(75,69,53)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun paintTrack(p0: Graphics?, p1: JComponent?, p2: Rectangle?) {}
|
||||||
|
|
||||||
|
override fun createDecreaseButton(p0: Int): JButton {
|
||||||
|
return object : JButton() {
|
||||||
|
override fun getPreferredSize(): Dimension {
|
||||||
|
return Dimension()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createIncreaseButton(p0: Int): JButton {
|
||||||
|
return object : JButton() {
|
||||||
|
override fun getPreferredSize(): Dimension {
|
||||||
|
return Dimension()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getVerticalScrollBar().background = Color(49,45,37)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeComments(node: Node) {
|
||||||
|
var i = 0
|
||||||
|
while (i < node.childNodeSize()) {
|
||||||
|
val child = node.childNode(i)
|
||||||
|
if (child.nodeName() == "#comment") child.remove()
|
||||||
|
else {
|
||||||
|
removeComments(child)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
153
src/main/kotlin/MainWindow.kt
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
import java.awt.Desktop
|
||||||
|
import java.awt.Dimension
|
||||||
|
import java.awt.Image
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URI
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
import javax.swing.*
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
|
||||||
|
object MainWindow : JFrame("2009scape Launcher") {
|
||||||
|
|
||||||
|
val loadingLabel = JLabel("Press Launch to play 2009scape!")
|
||||||
|
val loadingBar = JLabel(ImageIcon(javaClass.getResource("/loadingBar.png")))
|
||||||
|
val playButton = ImgButton("/playButton.png","/playButtonDisabled.png", false)
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
defaultCloseOperation = EXIT_ON_CLOSE
|
||||||
|
preferredSize = Dimension(1366,768)
|
||||||
|
size = Dimension(800,500)
|
||||||
|
val tileBG = BackgroundPanel(ImageIO.read(javaClass.getResource("/tile.png")))
|
||||||
|
contentPane = tileBG
|
||||||
|
layout = null
|
||||||
|
|
||||||
|
constructTopBar()
|
||||||
|
val updatePane = LatestUpdatePane("https://2009scape.org/services/m=news/archives/2021-07-12.html")
|
||||||
|
updatePane.placeAt(4, 45, MainWindow.width - 8, MainWindow.height - 85)
|
||||||
|
add(updatePane)
|
||||||
|
addPlayButton()
|
||||||
|
|
||||||
|
setLocationRelativeTo(null)
|
||||||
|
isUndecorated = true
|
||||||
|
isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun constructTopBar(){
|
||||||
|
val panel = BackgroundPanel(ImageIO.read(javaClass.getResource("/topBar.png")))
|
||||||
|
panel.placeAt(0,0,MainWindow.width, 40)
|
||||||
|
addCloseButton(panel)
|
||||||
|
addNewsButton(panel)
|
||||||
|
addBugReportButton(panel)
|
||||||
|
addHighscoreButton(panel)
|
||||||
|
addDiscordButton(panel)
|
||||||
|
addLogo(panel)
|
||||||
|
add(panel)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addPlayButton(){
|
||||||
|
val loadingFrame = JLabel(ImageIcon(javaClass.getResource("/loadingFrame.png")))
|
||||||
|
playButton.isEnabled = true
|
||||||
|
playButton.onClick {
|
||||||
|
if(Updater.checkUpdate()) Updater.runUpdate()
|
||||||
|
else Runtime.getRuntime().exec("java -jar " + Settings.SAVE_DIR + File.separator + Settings.SAVE_NAME, null, File(System.getProperty("user.home"))).also { exitProcess(0) }
|
||||||
|
}
|
||||||
|
loadingFrame.placeAt(96,MainWindow.height - 35, 704, 35)
|
||||||
|
loadingBar.placeAt(103, MainWindow.height - 33, 695, 31)
|
||||||
|
playButton.placeAt(0,MainWindow.height - 35,100,35)
|
||||||
|
loadingLabel.placeAt(300, MainWindow.height - 24, 300, 15)
|
||||||
|
add(loadingLabel)
|
||||||
|
add(loadingBar)
|
||||||
|
add(loadingFrame)
|
||||||
|
add(playButton)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addNewsButton(panel: JPanel){
|
||||||
|
val label = BackgroundLabel("/messageBox.png", "Latest<br/>Update")
|
||||||
|
label.placeAt(0, 40, 90, 56)
|
||||||
|
add(label)
|
||||||
|
|
||||||
|
val button = ImgButton("/news.png")
|
||||||
|
button.onMouseEnter { label.isVisible = true }
|
||||||
|
button.onMouseExit { label.isVisible = false }
|
||||||
|
button.onClick {
|
||||||
|
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
||||||
|
Desktop.getDesktop().browse(URI("https://2009scape.org/services/m=news/archives/2021-07-12.html"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button.placeAt(5,4,35,35)
|
||||||
|
panel.add(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addBugReportButton(panel: JPanel){
|
||||||
|
val label = BackgroundLabel("/messageBox.png", "Report<br/>Bug")
|
||||||
|
label.placeAt(25, 40, 90, 56)
|
||||||
|
add(label)
|
||||||
|
|
||||||
|
val button = ImgButton("/reportBug.png")
|
||||||
|
button.onMouseEnter { label.isVisible = true }
|
||||||
|
button.onMouseExit { label.isVisible = false }
|
||||||
|
button.onClick {
|
||||||
|
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
||||||
|
Desktop.getDesktop().browse(URI("https://gitlab.com/2009scape/2009scape/-/issues"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button.placeAt(50, 4, 35, 35)
|
||||||
|
panel.add(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addHighscoreButton(panel: JPanel){
|
||||||
|
val label = BackgroundLabel("/messageBox.png", "Leader<br/>Boards")
|
||||||
|
label.placeAt(70, 40, 90, 56)
|
||||||
|
add(label)
|
||||||
|
|
||||||
|
val button = ImgButton("/highScores.png")
|
||||||
|
button.onMouseEnter { label.isVisible = true }
|
||||||
|
button.onMouseExit { label.isVisible = false }
|
||||||
|
button.onClick {
|
||||||
|
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
||||||
|
Desktop.getDesktop().browse(URI("https://2009scape.org/services/m=hiscore/hiscores.html?world=2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button.placeAt(90, 2, 38, 38)
|
||||||
|
panel.add(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addDiscordButton(panel: JPanel){
|
||||||
|
val label = BackgroundLabel("/messageBox.png", "Join<br/>Discord")
|
||||||
|
label.placeAt(110, 40, 90, 56)
|
||||||
|
add(label)
|
||||||
|
|
||||||
|
val button = ImgButton("/joinDiscord.png")
|
||||||
|
button.onMouseEnter { label.isVisible = true }
|
||||||
|
button.onMouseExit { label.isVisible = false }
|
||||||
|
button.onClick {
|
||||||
|
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
||||||
|
Desktop.getDesktop().browse(URI("https://discord.gg/YY7WSttN7H"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button.placeAt(135, 4, 35, 35)
|
||||||
|
panel.add(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addCloseButton(panel: BackgroundPanel){
|
||||||
|
val button = ImgButton("/close_hi.png","/close_dark.png")
|
||||||
|
button.onClick { exitProcess(0) }
|
||||||
|
button.placeAt(panel.width - 35, 7, 25, 25)
|
||||||
|
button.isOpaque = false
|
||||||
|
panel.add(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addLogo(panel: JPanel){
|
||||||
|
val logo = JLabel(ImageIcon(javaClass.getResource("/logo.png")))
|
||||||
|
logo.icon = ImageIcon((logo.icon as ImageIcon).image.getScaledInstance(179,40, Image.SCALE_SMOOTH))
|
||||||
|
logo.placeAt(311, 0, 179, 40)
|
||||||
|
panel.add(logo)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/main/kotlin/Settings.kt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
object Settings {
|
||||||
|
val SAVE_DIR = System.getProperty("user.home")
|
||||||
|
val SAVE_NAME = "2009scape.jar"
|
||||||
|
val DOWNLOAD_URL = "http://play.2009scape.org/2009scape.jar"
|
||||||
|
}
|
||||||
86
src/main/kotlin/Updater.kt
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
import java.awt.Image
|
||||||
|
import java.io.File
|
||||||
|
import java.io.RandomAccessFile
|
||||||
|
import java.net.URL
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import javax.swing.ImageIcon
|
||||||
|
|
||||||
|
object Updater {
|
||||||
|
|
||||||
|
private var status = UpdateStatus.DOWNLOADING
|
||||||
|
|
||||||
|
fun checkUpdate(): Boolean{
|
||||||
|
val localMD5 = Checksum.getLocalChecksum(Settings.SAVE_DIR + File.separator + Settings.SAVE_NAME)
|
||||||
|
val remoteMD5 = Checksum.getRemoteChecksum(Settings.DOWNLOAD_URL)
|
||||||
|
|
||||||
|
return localMD5 != remoteMD5
|
||||||
|
}
|
||||||
|
|
||||||
|
fun runUpdate(){
|
||||||
|
val t = Thread() {
|
||||||
|
var oldText = MainWindow.loadingLabel.text
|
||||||
|
MainWindow.loadingLabel.text = "Updating client..."
|
||||||
|
MainWindow.playButton.isEnabled = false
|
||||||
|
var downloaded = 0
|
||||||
|
var lastBarUpdate = 0
|
||||||
|
|
||||||
|
val connection = URL(Settings.DOWNLOAD_URL).openConnection()
|
||||||
|
connection.connect()
|
||||||
|
|
||||||
|
val length = connection.contentLength
|
||||||
|
|
||||||
|
if (!File(Settings.SAVE_DIR).exists()) {
|
||||||
|
File(Settings.SAVE_DIR).mkdir()
|
||||||
|
}
|
||||||
|
if (File(Settings.SAVE_DIR + File.separator + Settings.SAVE_NAME).exists()) {
|
||||||
|
File(Settings.SAVE_DIR + File.separator + Settings.SAVE_NAME).delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
File(Settings.SAVE_DIR + File.separator + Settings.SAVE_NAME).createNewFile()
|
||||||
|
|
||||||
|
val file = RandomAccessFile(Settings.SAVE_DIR + File.separator + Settings.SAVE_NAME, "rw")
|
||||||
|
|
||||||
|
val stream = connection.getInputStream()
|
||||||
|
|
||||||
|
while(status == UpdateStatus.DOWNLOADING){
|
||||||
|
val buffer = if(length - downloaded > 1024){
|
||||||
|
ByteArray(1024)
|
||||||
|
} else {
|
||||||
|
ByteArray(length - downloaded)
|
||||||
|
}
|
||||||
|
|
||||||
|
val read = stream.read(buffer)
|
||||||
|
|
||||||
|
if(read == -1) break
|
||||||
|
|
||||||
|
val progress = ((downloaded / length.toFloat()) * 100).toInt()
|
||||||
|
val barLength = 1 + ((progress / 100.0) * 695.0).toInt()
|
||||||
|
|
||||||
|
MainWindow.loadingLabel.text = "Updating client... $progress%"
|
||||||
|
|
||||||
|
if(barLength - lastBarUpdate > 5){
|
||||||
|
MainWindow.loadingBar.icon = ImageIcon((MainWindow.loadingBar.icon as ImageIcon).image.getScaledInstance(barLength, 31, Image.SCALE_FAST))
|
||||||
|
MainWindow.loadingBar.placeAt(103, MainWindow.height - 33, barLength, 31)
|
||||||
|
lastBarUpdate = barLength
|
||||||
|
}
|
||||||
|
|
||||||
|
file.write(buffer, 0, read)
|
||||||
|
downloaded += read
|
||||||
|
|
||||||
|
if(downloaded >= length){
|
||||||
|
MainWindow.loadingLabel.text = oldText
|
||||||
|
MainWindow.playButton.isEnabled = true
|
||||||
|
file.close()
|
||||||
|
status = UpdateStatus.COMPLETE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MainWindow.loadingBar.icon = ImageIcon((MainWindow.loadingBar.icon as ImageIcon).image.getScaledInstance(695, 31, Image.SCALE_FAST))
|
||||||
|
MainWindow.loadingBar.placeAt(103, MainWindow.height - 33, 695, 31)
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum class UpdateStatus{
|
||||||
|
DOWNLOADING,
|
||||||
|
COMPLETE
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/main/resources/close_dark.png
Normal file
|
After Width: | Height: | Size: 295 B |
BIN
src/main/resources/close_hi.png
Normal file
|
After Width: | Height: | Size: 316 B |
BIN
src/main/resources/highScores.png
Normal file
|
After Width: | Height: | Size: 382 B |
BIN
src/main/resources/joinDiscord.png
Normal file
|
After Width: | Height: | Size: 435 B |
BIN
src/main/resources/loadingBar.png
Normal file
|
After Width: | Height: | Size: 676 B |
BIN
src/main/resources/loadingFrame.png
Normal file
|
After Width: | Height: | Size: 731 B |
BIN
src/main/resources/logo.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/main/resources/messageBox.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
src/main/resources/news.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/main/resources/playButton.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/main/resources/playButtonDisabled.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/main/resources/reportBug.png
Normal file
|
After Width: | Height: | Size: 880 B |
BIN
src/main/resources/tile.png
Normal file
|
After Width: | Height: | Size: 652 B |
BIN
src/main/resources/topBar.png
Normal file
|
After Width: | Height: | Size: 366 B |