package xyz.brysonsteck.serverfordummies import kotlinx.coroutines.* import kotlinx.coroutines.javafx.JavaFx import org.rauschig.jarchivelib.* 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 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.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.scene.image.Image import javafx.scene.image.ImageView 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 lateinit private var currentDirectoryLabel: Label @FXML lateinit private var worldNameField: TextField @FXML lateinit private var seedField: TextField @FXML lateinit private var portSpinner: Spinner @FXML lateinit private var difficultyBox: ChoiceBox @FXML lateinit private var gamemodeBox: ChoiceBox @FXML lateinit private var worldTypeBox: ChoiceBox @FXML lateinit private var worldSettingsPane: HBox @FXML lateinit private var parentPane: Pane @FXML lateinit private var directoryPane: 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 @FXML lateinit private var maxSizeSpinner: Spinner @FXML lateinit private var memorySpinner: Spinner @FXML lateinit private var spawnSpinner: Spinner @FXML lateinit private var simulationSpinner: Spinner @FXML lateinit private var renderSpinner: Spinner @FXML lateinit private var maxTickSpinner: Spinner @FXML lateinit private var statusBar: Label @FXML lateinit private var progressBar: ProgressBar @FXML lateinit private var startButton: Button @FXML lateinit private var buildButton: Button private var building = false @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 val real = loadServerDir(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() { } @FXML private fun onBuild() { if (building) { building = false return; } building = true worldSettingsPane.isDisable = true directoryPane.isDisable = true parentPane.isDisable = true startButton.isDisable = true buildButton.text = "Cancel Build" @Suppress("OPT_IN_USAGE") GlobalScope.launch(Dispatchers.Default) { progressBar.isVisible = true var downloads = mapOf( "BuildTools" to "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar", ) downloads.forEach { withContext(Dispatchers.JavaFx){statusBar.text = "Downloading ${it.key}..."} val download = Download(URL(it.value)) 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 update the progress bar print("") if (prog >= 0.01) { withContext(Dispatchers.JavaFx) {progressBar.progress = prog} } if (!building) download.status = Download.Status.CANCELLED Thread.sleep(300) } } progressBar.isVisible = false withContext(Dispatchers.JavaFx){ worldSettingsPane.isDisable = false directoryPane.isDisable = false parentPane.isDisable = false startButton.isDisable = false buildButton.text = "Build Server" statusBar.text = if (building) {"Ready."} else {"Server build cancelled."} building = false; } } } @FXML private fun onStart() { statusBar.text = "The Minecraft Server is now running. Shutdown the server to unlock the settings." @Suppress("OPT_IN_USAGE") GlobalScope.launch(Dispatchers.Default) { val proc = Runtime.getRuntime().exec("java -jar /home/bryson/test/testserver/server.jar"); } } private fun createDialog(type: String, msg: String, yes: String, no: String) { val resources = this.javaClass.getResource("icons/$type.png") val dialog = Stage(); dialog.initModality(Modality.APPLICATION_MODAL); val scenePane = Pane() val dialogScene = Scene(scenePane, 400.0, 150.0); val imagePane = Pane() val icon = Image("$resources") imagePane.layoutX = 14.0 imagePane.layoutY = 14.0 imagePane.scaleX = 0.7 imagePane.scaleY = 0.7 imagePane.children.add(ImageView(icon)) val label = Label(msg) label.layoutX = 115.0 label.layoutY = 40.0 val buttonBar = ButtonBar() buttonBar.padding = Insets(10.0, 10.0, 10.0, 10.0) buttonBar.layoutX = 0.0 buttonBar.layoutY = 107.0 buttonBar.prefWidth = 400.0 val noButton = Button(no) val yesButton = Button(yes) yesButton.isDefaultButton = true buttonBar.buttons.add(noButton) buttonBar.buttons.add(yesButton) scenePane.children.addAll(imagePane, label, buttonBar) dialog.setScene(dialogScene); dialog.show(); } private fun loadServerDir(dir: String): Boolean { createDialog("info", "There is no server in this directory.\nCreate one?", "Yes", "No") 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; } }