diff options
17 files changed, 254 insertions, 511 deletions
@@ -3,6 +3,7 @@ # Ignore Gradle build output directory build +bin # Ignore VSCode settings .vscode diff --git a/app/bin/main/xyz/brysonsteck/serverfordummies/App.kt b/app/bin/main/xyz/brysonsteck/serverfordummies/App.kt deleted file mode 100644 index 0547a8f..0000000 --- a/app/bin/main/xyz/brysonsteck/serverfordummies/App.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package xyz.brysonsteck.serverfordummies - -import javafx.application.Application; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.stage.Stage; - -class App : Application() { - - override fun start(stage: Stage) { - var scene = Scene(loadFXML("primary"), 1500.0, 900.0) - stage.title = "Server For Dummies" - stage.scene = scene - stage.show() - } - - private fun loadFXML(fxml: String) : Parent { - val fxmlLoader = FXMLLoader(this.javaClass.getResource(fxml + ".fxml")) - return fxmlLoader.load() - } - - public fun run() { - launch() - } - -} diff --git a/app/bin/main/xyz/brysonsteck/serverfordummies/Main.kt b/app/bin/main/xyz/brysonsteck/serverfordummies/Main.kt deleted file mode 100644 index 604825f..0000000 --- a/app/bin/main/xyz/brysonsteck/serverfordummies/Main.kt +++ /dev/null @@ -1,5 +0,0 @@ -package xyz.brysonsteck.serverfordummies - -fun main() { - App().run() -}
\ No newline at end of file diff --git a/app/bin/main/xyz/brysonsteck/serverfordummies/PrimaryController.kt b/app/bin/main/xyz/brysonsteck/serverfordummies/PrimaryController.kt deleted file mode 100644 index 6e05579..0000000 --- a/app/bin/main/xyz/brysonsteck/serverfordummies/PrimaryController.kt +++ /dev/null @@ -1,124 +0,0 @@ -package xyz.brysonsteck.serverfordummies - -import java.io.File -import java.io.IOException -import java.awt.Checkbox -import java.util.Properties - -import javafx.beans.value.ChangeListener -import javafx.beans.value.ObservableValue -import javafx.beans.property.BooleanProperty -import javafx.collections.FXCollections -import javafx.fxml.FXML -import javafx.geometry.Insets -import javafx.scene.control.Button -import javafx.scene.control.ChoiceBox -import javafx.scene.control.Label -import javafx.scene.control.TextField -import javafx.scene.control.Spinner -import javafx.scene.control.TitledPane -import javafx.scene.control.ButtonBar -import javafx.scene.control.CheckBox -import javafx.scene.layout.Border -import javafx.scene.layout.BorderStroke -import javafx.scene.layout.GridPane -import javafx.scene.layout.Pane -import javafx.scene.layout.HBox -import javafx.scene.text.TextAlignment -import javafx.scene.Scene -import javafx.scene.input.MouseEvent -import javafx.stage.FileChooser -import javafx.stage.FileChooser.ExtensionFilter -import javafx.stage.DirectoryChooser -import javafx.event.EventHandler - -class PrimaryController { - @FXML - lateinit private var currentDirectoryLabel: Label - @FXML - lateinit private var worldNameField: TextField - @FXML - lateinit private var seedField: TextField - @FXML - lateinit private var portSpinner: Spinner<kotlin.Int> - @FXML - lateinit private var difficultyBox: ChoiceBox<String> - @FXML - lateinit private var gamemodeBox: ChoiceBox<String> - @FXML - lateinit private var worldTypeBox: ChoiceBox<String> - @FXML - lateinit private var worldSettingsPane: HBox - @FXML - lateinit private var parentPane: Pane - @FXML - lateinit private var buttonBar: ButtonBar - @FXML - lateinit private var flightCheckbox: CheckBox - @FXML - lateinit private var netherCheckbox: CheckBox - @FXML - lateinit private var structuresCheckbox: CheckBox - @FXML - lateinit private var pvpCheckbox: CheckBox - @FXML - lateinit private var whitelistCheckbox: CheckBox - @FXML - lateinit private var cmdBlocksCheckbox: CheckBox - @FXML - lateinit private var playerCountCheckbox: CheckBox - @FXML - lateinit private var maxPlayersSpinner: Spinner<kotlin.Int> - @FXML - lateinit private var maxSizeSpinner: Spinner<kotlin.Int> - @FXML - lateinit private var memorySpinner: Spinner<kotlin.Int> - @FXML - lateinit private var spawnSpinner: Spinner<kotlin.Int> - @FXML - lateinit private var simulationSpinner: Spinner<kotlin.Int> - @FXML - lateinit private var renderSpinner: Spinner<kotlin.Int> - @FXML - lateinit private var maxTickSpinner: Spinner<kotlin.Int> - @FXML - lateinit private var progressBar: ProgressBar - - @FXML - private fun onDirectoryButtonClick() { - val dirChooser = DirectoryChooser() - dirChooser.title = "Open a server directory" - dirChooser.initialDirectory = File(System.getProperty("user.home")) - val result = dirChooser.showDialog(null) - if (result != null) { - currentDirectoryLabel.text = result.absolutePath - parentPane.isDisable = false - worldSettingsPane.isDisable = false - buttonBar.isDisable = false - } - } - - @FXML - private fun onWorldNameChange() { - - } - - @FXML - private fun onSeedChange() { - - } - - @FXML - private fun onPortChange() { - - } - - @FXML - private fun onCheckboxClick() { - } - - @FXML - private fun onSpinnerChange() { - - } -}
\ No newline at end of file diff --git a/app/bin/main/xyz/brysonsteck/serverfordummies/downloadFile.kt b/app/bin/main/xyz/brysonsteck/serverfordummies/downloadFile.kt deleted file mode 100644 index bbaeab5..0000000 --- a/app/bin/main/xyz/brysonsteck/serverfordummies/downloadFile.kt +++ /dev/null @@ -1,37 +0,0 @@ -import java.net.http.HttpClient -import kotlinx.coroutines.flow - -sealed class DownloadStatus { - - object Success : DownloadStatus() - - data class Error(val message: String) : DownloadStatus() - - data class Progress(val progress: Int): DownloadStatus() - -} - -// function from https://gist.githubusercontent.com/SG-K/63e379efcc3d1cd3ce4fb56ee0e29c42/raw/cd9a4a016401b7c54ec01303415b5871ffa26066/downloadFile.kt -suspend fun HttpClient.downloadFile(file: File, url: String): Flow<DownloadStatus> { - return flow { - val response = call { - url(url) - method = HttpMethod.Get - }.response - val byteArray = ByteArray(response.contentLength()!!.toInt()) - var offset = 0 - do { - val currentRead = response.content.readAvailable(byteArray, offset, byteArray.size) - offset += currentRead - val progress = (offset * 100f / byteArray.size).roundToInt() - emit(DownloadStatus.Progress(progress)) - } while (currentRead > 0) - response.close() - if (response.status.isSuccess()) { - file.writeBytes(byteArray) - emit(DownloadStatus.Success) - } else { - emit(DownloadStatus.Error("File not downloaded")) - } - } -}
\ No newline at end of file diff --git a/app/bin/main/xyz/brysonsteck/serverfordummies/primary.fxml b/app/bin/main/xyz/brysonsteck/serverfordummies/primary.fxml deleted file mode 100644 index 85b7370..0000000 --- a/app/bin/main/xyz/brysonsteck/serverfordummies/primary.fxml +++ /dev/null @@ -1,253 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<?import javafx.geometry.Insets?> -<?import javafx.scene.control.Button?> -<?import javafx.scene.control.ButtonBar?> -<?import javafx.scene.control.CheckBox?> -<?import javafx.scene.control.ChoiceBox?> -<?import javafx.scene.control.ContextMenu?> -<?import javafx.scene.control.Label?> -<?import javafx.scene.control.MenuItem?> -<?import javafx.scene.control.ProgressBar?> -<?import javafx.scene.control.Separator?> -<?import javafx.scene.control.Spinner?> -<?import javafx.scene.control.TextField?> -<?import javafx.scene.control.TitledPane?> -<?import javafx.scene.control.Tooltip?> -<?import javafx.scene.layout.AnchorPane?> -<?import javafx.scene.layout.HBox?> -<?import javafx.scene.layout.Pane?> -<?import javafx.scene.text.Font?> - -<Pane fx:id="primary" maxHeight="900.0" maxWidth="1500.0" minHeight="620.0" minWidth="963.0" prefHeight="708.0" prefWidth="963.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.brysonsteck.serverfordummies.PrimaryController"> - <children> - <HBox prefHeight="39.0" prefWidth="963.0"> - <children> - <Button id="openFile" fx:id="chooseDirectoryButton" lineSpacing="10.0" mnemonicParsing="false" onMouseClicked="#onDirectoryButtonClick" text="Choose Directory..."> - <opaqueInsets> - <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> - </opaqueInsets> - <HBox.margin> - <Insets /> - </HBox.margin> - </Button> - <Separator orientation="VERTICAL" prefHeight="200.0"> - <HBox.margin> - <Insets left="5.0" /> - </HBox.margin> - </Separator> - <Label text="Server Directory:"> - <HBox.margin> - <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> - </HBox.margin> - <font> - <Font name="System Bold" size="13.0" /> - </font> - </Label> - <Label id="currentFilename" fx:id="currentDirectoryLabel" text="<NONE>"> - <HBox.margin> - <Insets bottom="5.0" right="5.0" top="5.0" /> - </HBox.margin> - </Label> - </children> - <padding> - <Insets bottom="7.0" left="7.0" right="7.0" top="7.0" /> - </padding> - </HBox> - <HBox fx:id="worldSettingsPane" disable="true" layoutY="39.0" prefHeight="41.0" prefWidth="963.0"> - <padding> - <Insets bottom="7.0" left="7.0" right="7.0" top="7.0" /> - </padding> - <children> - <Label text="World Name:"> - <font> - <Font name="System Bold" size="13.0" /> - </font> - <HBox.margin> - <Insets bottom="5.0" left="5.0" right="5.0" top="6.0" /> - </HBox.margin> - </Label> - <TextField fx:id="worldNameField" onInputMethodTextChanged="#onWorldNameChange"> - <HBox.margin> - <Insets top="2.0" /> - </HBox.margin> - </TextField> - <Separator orientation="VERTICAL" prefHeight="200.0"> - <HBox.margin> - <Insets left="5.0" /> - </HBox.margin> - </Separator> - <Label text="Seed:"> - <font> - <Font name="System Bold" size="13.0" /> - </font> - <HBox.margin> - <Insets bottom="5.0" left="5.0" right="5.0" top="6.0" /> - </HBox.margin> - </Label> - <TextField fx:id="seedField" onInputMethodTextChanged="#onSeedChange" prefHeight="23.0" prefWidth="448.0"> - <HBox.margin> - <Insets top="2.0" /> - </HBox.margin> - </TextField> - <Separator orientation="VERTICAL" prefHeight="200.0"> - <HBox.margin> - <Insets left="5.0" /> - </HBox.margin> - </Separator> - <Label text="Server Port:"> - <font> - <Font name="System Bold" size="13.0" /> - </font> - <HBox.margin> - <Insets bottom="5.0" left="5.0" right="5.0" top="6.0" /> - </HBox.margin> - </Label> - <Spinner fx:id="portSpinner" onInputMethodTextChanged="#onPortChange" prefHeight="23.0" prefWidth="112.0"> - <HBox.margin> - <Insets top="2.0" /> - </HBox.margin> - </Spinner> - </children> - <opaqueInsets> - <Insets bottom="3.0" /> - </opaqueInsets> - </HBox> - <Pane fx:id="parentPane" disable="true" layoutY="78.0" prefHeight="555.0" prefWidth="970.0"> - <children> - <TitledPane fx:id="settingsPane" animated="false" collapsible="false" layoutX="10.0" layoutY="7.0" prefHeight="273.0" prefWidth="627.0" text="Server Settings"> - <content> - <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="311.0" prefWidth="625.0"> - <children> - <CheckBox fx:id="flightCheckbox" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" text="Allow Flight" /> - <CheckBox fx:id="netherCheckbox" layoutX="14.0" layoutY="42.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" text="Allow The Nether" /> - <CheckBox fx:id="structuresCheckbox" alignment="TOP_LEFT" layoutX="14.0" layoutY="70.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" prefHeight="45.0" prefWidth="231.0" text="Generate Structures (such as villages and strongholds)" /> - <CheckBox fx:id="pvpCheckbox" layoutX="14.0" layoutY="109.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" text="Allow PvP" /> - <CheckBox fx:id="whitelistCheckbox" alignment="TOP_LEFT" layoutX="14.0" layoutY="138.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" prefHeight="45.0" prefWidth="231.0" text="Enable Whitelist (Only users you specify can join)" /> - <Spinner fx:id="maxPlayerSpinner" layoutX="130.0" layoutY="179.0" prefHeight="23.0" prefWidth="99.0" /> - <Label layoutX="14.0" layoutY="183.0" text="Maximum Players:" /> - <Spinner fx:id="maxSizeSpinner" layoutX="214.0" layoutY="212.0" prefHeight="23.0" prefWidth="155.0" /> - <Label layoutX="14.0" layoutY="216.0" text="Maximum World Size (in blocks):" /> - </children> - </AnchorPane> - </content> - </TitledPane> - <TitledPane fx:id="advancedPane" animated="false" layoutX="10.0" layoutY="289.0" prefHeight="259.0" prefWidth="627.0" text="Advanced Server Settings"> - <content> - <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="269.0" prefWidth="625.0"> - <children> - <CheckBox fx:id="cmdBlocksCheckbox" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" text="Enable Command Blocks" /> - <CheckBox fx:id="playerCountCheckbox" layoutX="14.0" layoutY="41.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" text="Hide Online Player Count" /> - <Spinner fx:id="memorySpinner" layoutX="154.0" layoutY="69.0" prefHeight="23.0" prefWidth="99.0" /> - <Label ellipsisString="" layoutX="14.0" layoutY="73.0" text="Server Memory in MB:" textOverrun="CLIP"> - <tooltip> - <Tooltip text="This is the amount of RAM that will get passed to Minecraft/the JVM. For simple servers, 1024 MB will be plenty. If you typically have more than 5 concurrent players, consider allocating more." /> - </tooltip> - </Label> - <Spinner fx:id="spawnSpinner" layoutX="172.0" layoutY="100.0" prefHeight="23.0" prefWidth="99.0" /> - <Label layoutX="14.0" layoutY="104.0" text="Spawn Protection Radius:"> - <tooltip> - <Tooltip text="All blocks in a radius from 0,~,0 will be unbreakable. If you want to break blocks within spawn, change this value." /> - </tooltip> - </Label> - <Spinner fx:id="simulationSpinner" layoutX="147.0" layoutY="132.0" prefHeight="23.0" prefWidth="99.0" /> - <Label layoutX="14.0" layoutY="136.0" text="Simulation Distance:"> - <tooltip> - <Tooltip text="The radius of chunks for each player where ticks will be updated. In other words, anything outside these circles, such as furnaces, mobs, etc, will not be updated or simulated." /> - </tooltip> - </Label> - <Spinner fx:id="renderSpinner" layoutX="124.0" layoutY="165.0" prefHeight="23.0" prefWidth="99.0" /> - <Label layoutX="14.0" layoutY="169.0" text="Render Distance:"> - <tooltip> - <Tooltip text="The radius of chunks where the server will render the view distance. Any value higher on a client than what is set will be ignored. Higher values will be more demanding on the server." /> - </tooltip> - </Label> - <Label layoutX="14.0" layoutY="203.0" text="Maximum Tick Time (in milliseconds):"> - <tooltip> - <Tooltip text="If the server cannot update ticks (i.e. "lags") for longer than this amount of time, the server will shutdown. 60000 ms (60 seconds) is the default." /> - </tooltip> - </Label> - <Spinner fx:id="maxTickSpinner" layoutX="246.0" layoutY="199.0" prefHeight="23.0" prefWidth="99.0" /> - </children> - </AnchorPane> - </content> - </TitledPane> - <TitledPane fx:id="difficultyPane" animated="false" collapsible="false" layoutX="649.0" layoutY="7.0" prefHeight="77.0" prefWidth="305.0" text="Difficulty"> - <content> - <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="94.0" prefWidth="303.0"> - <children> - <ChoiceBox fx:id="difficultyBox" layoutX="14.0" layoutY="14.0" prefHeight="23.0" prefWidth="276.0"> - <contextMenu> - <ContextMenu> - <items> - <MenuItem mnemonicParsing="false" /> - </items> - </ContextMenu> - </contextMenu> - </ChoiceBox> - </children> - </AnchorPane> - </content> - </TitledPane> - <TitledPane fx:id="gamemodePane" animated="false" collapsible="false" layoutX="649.0" layoutY="92.0" prefHeight="77.0" prefWidth="305.0" text="Gamemode"> - <content> - <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="94.0" prefWidth="303.0"> - <children> - <ChoiceBox fx:id="gamemodeBox" layoutX="14.0" layoutY="14.0" prefHeight="23.0" prefWidth="276.0" /> - </children> - </AnchorPane> - </content> - </TitledPane> - <TitledPane fx:id="worldTypePane" animated="false" collapsible="false" layoutX="649.0" layoutY="178.0" prefHeight="77.0" prefWidth="305.0" text="World Type"> - <content> - <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="94.0" prefWidth="303.0"> - <children> - <ChoiceBox fx:id="worldTypeBox" layoutX="14.0" layoutY="14.0" prefHeight="23.0" prefWidth="276.0" /> - </children> - </AnchorPane> - </content> - </TitledPane> - <TitledPane fx:id="worldTypePane1" animated="false" collapsible="false" layoutX="649.0" layoutY="265.0" prefHeight="283.0" prefWidth="305.0" text="Whitelist"> - <content> - <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="94.0" prefWidth="303.0"> - <children> - <ChoiceBox layoutX="14.0" layoutY="14.0" prefHeight="23.0" prefWidth="276.0" /> - </children> - </AnchorPane> - </content> - </TitledPane> - </children> - </Pane> - <ButtonBar fx:id="buttonBar" disable="true" layoutY="635.0" prefHeight="40.0" prefWidth="963.0"> - <buttons> - <Button mnemonicParsing="false" text="Build Server" /> - <Button defaultButton="true" mnemonicParsing="false" text="Start Server" /> - </buttons> - <padding> - <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" /> - </padding> - </ButtonBar> - <HBox layoutY="680.0" prefHeight="33.0" prefWidth="963.0" style="-fx-background-color: ddd;"> - <children> - <Label text="Status:"> - <font> - <Font name="System Bold" size="13.0" /> - </font> - </Label> - <Label fx:id="statusBar" text="Ready."> - <HBox.margin> - <Insets left="5.0" /> - </HBox.margin> - </Label> - <ProgressBar fx:id="progressBar" prefWidth="400.0" progress="0.0" visible="false"> - <HBox.margin> - <Insets left="460.0" /> - </HBox.margin> - </ProgressBar> - </children> - <padding> - <Insets bottom="9.0" left="9.0" right="9.0" top="9.0" /> - </padding> - </HBox> - </children> -</Pane> diff --git a/app/bin/test/xyz/brysonsteck/serverfordummies/AppTest.kt b/app/bin/test/xyz/brysonsteck/serverfordummies/AppTest.kt deleted file mode 100644 index e1d1866..0000000 --- a/app/bin/test/xyz/brysonsteck/serverfordummies/AppTest.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package xyz.brysonsteck.serverfordummies - -import kotlin.test.Test -import kotlin.test.assertNotNull - -class AppTest { - // @Test fun appHasAGreeting() { - // val classUnderTest = App() - // assertNotNull(classUnderTest.greeting, "app should have a greeting") - // } -} diff --git a/app/build.gradle b/app/build.gradle index 8add66f..ac1dd3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. - id 'org.jetbrains.kotlin.jvm' version '1.6.0' + id 'org.jetbrains.kotlin.jvm' version '1.8.0' // Apply the application plugin to add support for building a CLI application in Java. id 'application' @@ -32,12 +32,9 @@ dependencies { // This dependency is used by the application. implementation 'com.google.guava:guava:31.1-jre' - // Ktor - implementation "io.ktor:ktor-server-core:2.3.0" - implementation "io.ktor:ktor-server-netty:2.3.0" - // Coroutines core - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.0" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-javafx:1.7.0" } application { @@ -63,4 +60,4 @@ tasks.named('test') { javafx { version = "20" modules = ['javafx.controls', 'javafx.fxml', 'javafx.graphics'] -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/App.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/App.kt index 0547a8f..cffa525 100644 --- a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/App.kt +++ b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/App.kt @@ -18,7 +18,7 @@ class App : Application() { stage.show() } - private fun loadFXML(fxml: String) : Parent { + public fun loadFXML(fxml: String) : Parent { val fxmlLoader = FXMLLoader(this.javaClass.getResource(fxml + ".fxml")) return fxmlLoader.load() } diff --git a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/Download.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/Download.kt new file mode 100644 index 0000000..da61f75 --- /dev/null +++ b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/Download.kt @@ -0,0 +1,119 @@ +import java.io.*; +import java.net.*; +import java.util.*; + +class Download: Runnable { + public enum class Status { + DOWNLOADING, PAUSED, COMPLETE, CANCELLED, ERROR + } + public var size: Int + public var downloaded: Int + public var contentLength: Int + + private final val MAX_BUFFER_SIZE: Number = 1024 + + private var url: URL + private var status: Status + + constructor (url: URL) { + this.url = url + size = -1 + downloaded = 0 + status = Status.DOWNLOADING + contentLength = 1 + } + + public fun status(): Status { + return status + } + + public fun start() { + val thread = Thread(this) + thread.start() + } + + private fun getFilename(url: URL): String { + val filename = url.getFile() + return filename.substring(filename.lastIndexOf('/') + 1) + } + + override fun run() { + var stream: InputStream? = null + var file: RandomAccessFile? = null + + try { + // Open connection to URL. + var connection = url.openConnection() as HttpURLConnection; + + // Specify what portion of file to download. + connection.setRequestProperty("Range", "bytes=" + downloaded + "-"); + + // Connect to server. + connection.connect(); + + // Make sure response code is in the 200 range. + if (connection.responseCode / 100 != 2) { + status = Status.ERROR + } + + // Check for valid content length. + contentLength = connection.getContentLength(); + if (contentLength < 1) { + status = Status.ERROR + } + + /* Set the size for this download if it + hasn't been already set. */ + if (size == -1) { + size = contentLength; + } + + // Open file and seek to the end of it. + file = RandomAccessFile(getFilename(url), "rw"); + file.seek(downloaded.toLong()); + + stream = connection.getInputStream(); + while (status == Status.DOWNLOADING) { + /* Size buffer according to how much of the + file is left to download. */ + val buffer: ByteArray; + if (size - downloaded > MAX_BUFFER_SIZE as Int) { + buffer = ByteArray(MAX_BUFFER_SIZE) + } else { + buffer = ByteArray(size - downloaded); + } + + // Read from server into buffer. + val read = stream.read(buffer); + if (read == -1) + break; + + // Write buffer to file. + file.write(buffer, 0, read); + downloaded += read; + } + + /* Change status to complete if this point was + reached because downloading has finished. */ + if (status == Status.DOWNLOADING) { + status = Status.COMPLETE; + } + } catch (e: Exception) { + status = Status.ERROR + } finally { + // Close file. + if (file != null) { + try { + file.close(); + } catch (e: Exception) {} + } + + // Close connection to server. + if (stream != null) { + try { + stream.close(); + } catch (e: Exception) {} + } + } + } +} diff --git a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/PrimaryController.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/PrimaryController.kt index 6e05579..ac45e2a 100644 --- a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/PrimaryController.kt +++ b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/PrimaryController.kt @@ -1,12 +1,17 @@ package xyz.brysonsteck.serverfordummies +import kotlinx.coroutines.* +import kotlinx.coroutines.javafx.JavaFx + import java.io.File import java.io.IOException import java.awt.Checkbox import java.util.Properties +import java.net.URL import javafx.beans.value.ChangeListener import javafx.beans.value.ObservableValue +import javafx.concurrent.Task import javafx.beans.property.BooleanProperty import javafx.collections.FXCollections import javafx.fxml.FXML @@ -19,18 +24,24 @@ import javafx.scene.control.Spinner import javafx.scene.control.TitledPane import javafx.scene.control.ButtonBar import javafx.scene.control.CheckBox +import javafx.scene.control.ProgressBar import javafx.scene.layout.Border import javafx.scene.layout.BorderStroke import javafx.scene.layout.GridPane import javafx.scene.layout.Pane import javafx.scene.layout.HBox +import javafx.scene.layout.VBox import javafx.scene.text.TextAlignment +import javafx.scene.text.Text import javafx.scene.Scene import javafx.scene.input.MouseEvent import javafx.stage.FileChooser import javafx.stage.FileChooser.ExtensionFilter import javafx.stage.DirectoryChooser +import javafx.stage.Modality +import javafx.stage.Stage import javafx.event.EventHandler +import Download class PrimaryController { @FXML @@ -82,6 +93,8 @@ class PrimaryController { @FXML lateinit private var maxTickSpinner: Spinner<kotlin.Int> @FXML + lateinit private var statusBar: Label + @FXML lateinit private var progressBar: ProgressBar @FXML @@ -92,6 +105,7 @@ class PrimaryController { val result = dirChooser.showDialog(null) if (result != null) { currentDirectoryLabel.text = result.absolutePath + val real = loadServerDir(result.absolutePath) parentPane.isDisable = false worldSettingsPane.isDisable = false buttonBar.isDisable = false @@ -115,10 +129,91 @@ class PrimaryController { @FXML private fun onCheckboxClick() { + } @FXML private fun onSpinnerChange() { } + + @FXML + private fun onBuild() { + GlobalScope.launch(Dispatchers.Default) { + withContext(Dispatchers.JavaFx){statusBar.text = "Downloading a file..."} + progressBar.isVisible = true + val download = Download(URL("https://brysonsteck.xyz/pub/a-really-big-file")) + download.start() + while (download.status() == Download.Status.DOWNLOADING) { + var prog = (download.downloaded.toDouble() / download.contentLength.toDouble()) + // for whatever reason I need to print something to the screen in order for it to work + print("") + if (prog >= 0.01) { + withContext(Dispatchers.JavaFx) {progressBar.progress = prog} + } + Thread.sleep(300) + } + progressBar.isVisible = false + withContext(Dispatchers.JavaFx){statusBar.text = "Ready."} + } + } + + @FXML + private fun onStart() { + + } + + private fun createDialog() { + val dialog = Stage(); + dialog.initModality(Modality.APPLICATION_MODAL); + val dialogScene = Scene(App().loadFXML("dialog"), 300.0, 200.0); + dialog.setScene(dialogScene); + dialog.show(); + } + + private fun loadServerDir(dir: String): Boolean { + createDialog() + var directory = dir + var hasServer = false + if (!File(directory).isDirectory) { + return false; + } + + if (directory[directory.length-1] != File.separatorChar) + directory += File.separatorChar + + val hasDummy = File(directory + "ServerForDummies").isDirectory + + for (i in 20 downTo 8) { + for (j in 15 downTo 0) { + var spigotFile: String = "" + if (j == 0) + spigotFile += "spigot-1.$i.jar" + else + spigotFile += "spigot-1.$i.$j.jar"; + + hasServer = File(directory + spigotFile).isFile || File(directory + "server.jar").isFile + if (hasServer) + break; + } + } + + val hasProperties = File(directory + File.separator + "server.properties").isFile + + if (hasDummy && hasServer) { + // read jproperties + println("read jproperties") + } else if (hasDummy && !hasServer && hasProperties) { + // just needs to be built + println("build") + } else if (!hasDummy && hasServer) { + // server created externally + println("server made externally") + } else { + // assume clean directory + println("none") + } + + return true; + } }
\ No newline at end of file diff --git a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/downloadFile.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/downloadFile.kt deleted file mode 100644 index bbaeab5..0000000 --- a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/downloadFile.kt +++ /dev/null @@ -1,37 +0,0 @@ -import java.net.http.HttpClient -import kotlinx.coroutines.flow - -sealed class DownloadStatus { - - object Success : DownloadStatus() - - data class Error(val message: String) : DownloadStatus() - - data class Progress(val progress: Int): DownloadStatus() - -} - -// function from https://gist.githubusercontent.com/SG-K/63e379efcc3d1cd3ce4fb56ee0e29c42/raw/cd9a4a016401b7c54ec01303415b5871ffa26066/downloadFile.kt -suspend fun HttpClient.downloadFile(file: File, url: String): Flow<DownloadStatus> { - return flow { - val response = call { - url(url) - method = HttpMethod.Get - }.response - val byteArray = ByteArray(response.contentLength()!!.toInt()) - var offset = 0 - do { - val currentRead = response.content.readAvailable(byteArray, offset, byteArray.size) - offset += currentRead - val progress = (offset * 100f / byteArray.size).roundToInt() - emit(DownloadStatus.Progress(progress)) - } while (currentRead > 0) - response.close() - if (response.status.isSuccess()) { - file.writeBytes(byteArray) - emit(DownloadStatus.Success) - } else { - emit(DownloadStatus.Error("File not downloaded")) - } - } -}
\ No newline at end of file diff --git a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/server/Server.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/server/Server.kt new file mode 100644 index 0000000..16f250e --- /dev/null +++ b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/server/Server.kt @@ -0,0 +1,7 @@ +package xyz.brysonsteck.serverfordummies.server + +import java.io.File + +public class Server { + +}
\ No newline at end of file diff --git a/app/src/main/resources/xyz/brysonsteck/serverfordummies/dialog.fxml b/app/src/main/resources/xyz/brysonsteck/serverfordummies/dialog.fxml new file mode 100644 index 0000000..6dab79a --- /dev/null +++ b/app/src/main/resources/xyz/brysonsteck/serverfordummies/dialog.fxml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.ButtonBar?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.layout.Pane?> + + +<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1"> + <children> + <Pane fx:id="iconPane" layoutX="14.0" layoutY="14.0" prefHeight="82.0" prefWidth="82.0" /> + <Label fx:id="dialogLabel" layoutX="115.0" layoutY="40.0" text="Dialog Box" /> + <ButtonBar layoutY="157.0" prefHeight="43.0" prefWidth="400.0"> + <buttons> + <Button fx:id="otherButton" mnemonicParsing="false" text="Decline" /> + <Button fx:id="defaultButton" defaultButton="true" mnemonicParsing="false" text="Accept" /> + </buttons> + <padding> + <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> + </padding> + </ButtonBar> + </children> +</Pane> diff --git a/app/src/main/resources/xyz/brysonsteck/serverfordummies/icons/info.png b/app/src/main/resources/xyz/brysonsteck/serverfordummies/icons/info.png Binary files differnew file mode 100644 index 0000000..c1951a7 --- /dev/null +++ b/app/src/main/resources/xyz/brysonsteck/serverfordummies/icons/info.png diff --git a/app/src/main/resources/xyz/brysonsteck/serverfordummies/icons/warning.png b/app/src/main/resources/xyz/brysonsteck/serverfordummies/icons/warning.png Binary files differnew file mode 100644 index 0000000..4d66729 --- /dev/null +++ b/app/src/main/resources/xyz/brysonsteck/serverfordummies/icons/warning.png diff --git a/app/src/main/resources/xyz/brysonsteck/serverfordummies/primary.fxml b/app/src/main/resources/xyz/brysonsteck/serverfordummies/primary.fxml index 85b7370..c940d08 100644 --- a/app/src/main/resources/xyz/brysonsteck/serverfordummies/primary.fxml +++ b/app/src/main/resources/xyz/brysonsteck/serverfordummies/primary.fxml @@ -220,7 +220,7 @@ </Pane> <ButtonBar fx:id="buttonBar" disable="true" layoutY="635.0" prefHeight="40.0" prefWidth="963.0"> <buttons> - <Button mnemonicParsing="false" text="Build Server" /> + <Button mnemonicParsing="false" onMouseClicked="#onBuild" text="Build Server" /> <Button defaultButton="true" mnemonicParsing="false" text="Start Server" /> </buttons> <padding> @@ -239,9 +239,9 @@ <Insets left="5.0" /> </HBox.margin> </Label> - <ProgressBar fx:id="progressBar" prefWidth="400.0" progress="0.0" visible="false"> + <ProgressBar fx:id="progressBar" prefWidth="400.0" visible="false"> <HBox.margin> - <Insets left="460.0" /> + <Insets left="10.0" /> </HBox.margin> </ProgressBar> </children> |