diff options
Diffstat (limited to 'app/src')
6 files changed, 463 insertions, 0 deletions
diff --git a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/App.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/App.kt new file mode 100644 index 0000000..0547a8f --- /dev/null +++ b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/App.kt @@ -0,0 +1,30 @@ +/* + * 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/src/main/kotlin/xyz/brysonsteck/serverfordummies/Main.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/Main.kt new file mode 100644 index 0000000..604825f --- /dev/null +++ b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/Main.kt @@ -0,0 +1,5 @@ +package xyz.brysonsteck.serverfordummies + +fun main() { + App().run() +}
\ No newline at end of file diff --git a/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/PrimaryController.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/PrimaryController.kt new file mode 100644 index 0000000..6e05579 --- /dev/null +++ b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/PrimaryController.kt @@ -0,0 +1,124 @@ +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/src/main/kotlin/xyz/brysonsteck/serverfordummies/downloadFile.kt b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/downloadFile.kt new file mode 100644 index 0000000..bbaeab5 --- /dev/null +++ b/app/src/main/kotlin/xyz/brysonsteck/serverfordummies/downloadFile.kt @@ -0,0 +1,37 @@ +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/resources/xyz/brysonsteck/serverfordummies/primary.fxml b/app/src/main/resources/xyz/brysonsteck/serverfordummies/primary.fxml new file mode 100644 index 0000000..85b7370 --- /dev/null +++ b/app/src/main/resources/xyz/brysonsteck/serverfordummies/primary.fxml @@ -0,0 +1,253 @@ +<?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/src/test/kotlin/xyz/brysonsteck/serverfordummies/AppTest.kt b/app/src/test/kotlin/xyz/brysonsteck/serverfordummies/AppTest.kt new file mode 100644 index 0000000..e1d1866 --- /dev/null +++ b/app/src/test/kotlin/xyz/brysonsteck/serverfordummies/AppTest.kt @@ -0,0 +1,14 @@ +/* + * 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") + // } +} |