window resizing works, need to refine further
This commit is contained in:
parent
9a16ada0f6
commit
e674df1cd3
13 changed files with 721 additions and 710 deletions
|
@ -1,25 +1,26 @@
|
|||
package xyz.brysonsteck.ServerCraft
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.application.Application
|
||||
import javafx.fxml.FXMLLoader
|
||||
import javafx.scene.Parent
|
||||
import javafx.scene.Scene
|
||||
import javafx.scene.image.Image
|
||||
import javafx.stage.Stage;
|
||||
import java.awt.Desktop;
|
||||
import javafx.stage.Stage
|
||||
|
||||
class App : Application() {
|
||||
|
||||
override fun start(stage: Stage) {
|
||||
var scene = Scene(loadFXML("primary"), 963.0, 713.0)
|
||||
// Application.setUserAgentStylesheet(CupertinoLight().getUserAgentStylesheet())
|
||||
scene.stylesheets.add(this.javaClass.getResource("css/style.css").toExternalForm())
|
||||
stage.icons.add(Image(this.javaClass.getResourceAsStream("app.png")))
|
||||
stage.setResizable(false)
|
||||
stage.setResizable(true)
|
||||
stage.title = "ServerCraft"
|
||||
stage.scene = scene
|
||||
stage.show()
|
||||
}
|
||||
|
||||
public fun loadFXML(fxml: String) : Parent {
|
||||
public fun loadFXML(fxml: String): Parent {
|
||||
val fxmlLoader = FXMLLoader(this.javaClass.getResource(fxml + ".fxml"))
|
||||
return fxmlLoader.load()
|
||||
}
|
||||
|
@ -27,5 +28,4 @@ class App : Application() {
|
|||
public fun run() {
|
||||
launch()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,27 +1,21 @@
|
|||
package xyz.brysonsteck.ServerCraft.controllers
|
||||
|
||||
import java.awt.Desktop
|
||||
import java.net.URI
|
||||
import java.util.Properties
|
||||
import javafx.event.ActionEvent
|
||||
import javafx.fxml.FXML
|
||||
import javafx.application.Platform
|
||||
import javafx.scene.Node
|
||||
import javafx.scene.control.Hyperlink
|
||||
import javafx.scene.control.Label
|
||||
import javafx.stage.Stage
|
||||
import javafx.event.ActionEvent
|
||||
import java.awt.Desktop
|
||||
import java.net.URI
|
||||
import java.util.Properties
|
||||
import xyz.brysonsteck.ServerCraft.App
|
||||
|
||||
class InfoController {
|
||||
@FXML
|
||||
lateinit private var version: Label
|
||||
@FXML lateinit private var version: Label
|
||||
|
||||
private val emails = mapOf(
|
||||
"bryson" to "me@brysonsteck.xyz"
|
||||
)
|
||||
private val websites = mapOf(
|
||||
"bryson" to "https://brysonsteck.xyz"
|
||||
)
|
||||
private val emails = mapOf("bryson" to "me@brysonsteck.xyz")
|
||||
private val websites = mapOf("bryson" to "https://brysonsteck.xyz")
|
||||
private val source = "https://codeberg.org/brysonsteck/ServerCraft"
|
||||
private val license = "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
|
||||
|
@ -81,6 +75,6 @@ class InfoController {
|
|||
private fun closeInfo(e: ActionEvent) {
|
||||
val source = e.getSource() as Node
|
||||
val stage = source.getScene().getWindow() as Stage
|
||||
stage.close();
|
||||
stage.close()
|
||||
}
|
||||
}
|
|
@ -1,136 +1,76 @@
|
|||
package xyz.brysonsteck.ServerCraft.controllers
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.javafx.JavaFx
|
||||
import org.rauschig.jarchivelib.*
|
||||
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.awt.Checkbox
|
||||
import java.awt.Desktop
|
||||
import java.util.Properties
|
||||
import java.net.URL
|
||||
import java.net.URI
|
||||
|
||||
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.event.ActionEvent
|
||||
import javafx.fxml.FXML
|
||||
import javafx.fxml.FXMLLoader
|
||||
import javafx.geometry.Insets
|
||||
import javafx.scene.Scene
|
||||
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.ChoiceBox
|
||||
import javafx.scene.control.Label
|
||||
import javafx.scene.control.ProgressBar
|
||||
import javafx.scene.control.Hyperlink
|
||||
import javafx.scene.control.ScrollPane
|
||||
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.control.Spinner
|
||||
import javafx.scene.control.TextField
|
||||
import javafx.scene.image.Image
|
||||
import javafx.scene.image.ImageView
|
||||
import javafx.stage.FileChooser
|
||||
import javafx.stage.FileChooser.ExtensionFilter
|
||||
import javafx.scene.layout.HBox
|
||||
import javafx.scene.layout.Pane
|
||||
import javafx.stage.DirectoryChooser
|
||||
import javafx.stage.Modality
|
||||
import javafx.stage.Stage
|
||||
import javafx.event.EventHandler
|
||||
import javafx.event.ActionEvent
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.javafx.JavaFx
|
||||
import org.rauschig.jarchivelib.*
|
||||
|
||||
import xyz.brysonsteck.ServerCraft.server.Server
|
||||
import xyz.brysonsteck.ServerCraft.server.Download
|
||||
import xyz.brysonsteck.ServerCraft.App
|
||||
import xyz.brysonsteck.ServerCraft.dialogs.Dialog
|
||||
import xyz.brysonsteck.ServerCraft.dialogs.CommonDialog
|
||||
import xyz.brysonsteck.ServerCraft.dialogs.KillDialog
|
||||
import xyz.brysonsteck.ServerCraft.dialogs.Dialog
|
||||
import xyz.brysonsteck.ServerCraft.dialogs.EulaDialog
|
||||
import xyz.brysonsteck.ServerCraft.dialogs.KillDialog
|
||||
import xyz.brysonsteck.ServerCraft.server.Download
|
||||
import xyz.brysonsteck.ServerCraft.server.Server
|
||||
|
||||
class PrimaryController {
|
||||
@FXML
|
||||
lateinit private var primary: Pane
|
||||
@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 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 maxPlayerSpinner: 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 statusBar: Label
|
||||
@FXML
|
||||
lateinit private var progressBar: ProgressBar
|
||||
@FXML
|
||||
lateinit private var startButton: Button
|
||||
@FXML
|
||||
lateinit private var buildButton: Button
|
||||
@FXML
|
||||
lateinit private var defaultsButton: Button
|
||||
@FXML
|
||||
lateinit private var dropDownIcon: ImageView
|
||||
@FXML
|
||||
lateinit private var console: Label
|
||||
@FXML
|
||||
lateinit private var scrollPane: ScrollPane
|
||||
@FXML lateinit private var primary: Pane
|
||||
@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 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 maxPlayerSpinner: 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 statusBar: Label
|
||||
@FXML lateinit private var progressBar: ProgressBar
|
||||
@FXML lateinit private var startButton: Button
|
||||
@FXML lateinit private var buildButton: Button
|
||||
@FXML lateinit private var defaultsButton: Button
|
||||
@FXML lateinit private var dropDownIcon: ImageView
|
||||
@FXML lateinit private var console: Label
|
||||
@FXML lateinit private var scrollPane: ScrollPane
|
||||
|
||||
lateinit private var server: Server
|
||||
lateinit private var killDialog: Dialog
|
||||
|
@ -150,38 +90,25 @@ class PrimaryController {
|
|||
|
||||
@FXML
|
||||
public fun initialize() {
|
||||
scrollPane.vvalueProperty().bind(console.heightProperty());
|
||||
difficultyBox.items = FXCollections.observableArrayList(
|
||||
"Peaceful",
|
||||
"Easy",
|
||||
"Normal",
|
||||
"Hard",
|
||||
"Hardcore"
|
||||
)
|
||||
// scrollPane.vvalueProperty().bind(console.heightProperty());
|
||||
difficultyBox.items =
|
||||
FXCollections.observableArrayList("Peaceful", "Easy", "Normal", "Hard", "Hardcore")
|
||||
difficultyBox.value = "Normal"
|
||||
difficultyBox.selectionModel.selectedIndexProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("difficulty", difficultyBox.items[new as Int])
|
||||
}
|
||||
}
|
||||
gamemodeBox.items = FXCollections.observableArrayList(
|
||||
"Survival",
|
||||
"Creative",
|
||||
"Adventure",
|
||||
"Spectator"
|
||||
)
|
||||
gamemodeBox.items =
|
||||
FXCollections.observableArrayList("Survival", "Creative", "Adventure", "Spectator")
|
||||
gamemodeBox.value = "Survival"
|
||||
gamemodeBox.selectionModel.selectedIndexProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("gamemode", gamemodeBox.items[new as Int])
|
||||
}
|
||||
}
|
||||
worldTypeBox.items = FXCollections.observableArrayList(
|
||||
"Normal",
|
||||
"Superflat",
|
||||
"Large Biomes",
|
||||
"Amplified"
|
||||
)
|
||||
worldTypeBox.items =
|
||||
FXCollections.observableArrayList("Normal", "Superflat", "Large Biomes", "Amplified")
|
||||
worldTypeBox.value = "Normal"
|
||||
worldTypeBox.selectionModel.selectedIndexProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
|
@ -293,14 +220,17 @@ class PrimaryController {
|
|||
spawnSpinner.valueFactory.value = server.getProp("spawn-protection").toIntOrNull()
|
||||
simulationSpinner.valueFactory.value = server.getProp("simulation-distance").toIntOrNull()
|
||||
maxTickSpinner.valueFactory.value = server.getProp("max-tick-time").toIntOrNull()
|
||||
difficultyBox.value = if (parseBool(server.getProp("hardcore"))) {
|
||||
"Hardcore"
|
||||
} else {
|
||||
server.getProp("difficulty").replaceFirstChar { it.uppercase() }
|
||||
}
|
||||
difficultyBox.value =
|
||||
if (parseBool(server.getProp("hardcore"))) {
|
||||
"Hardcore"
|
||||
} else {
|
||||
server.getProp("difficulty").replaceFirstChar { it.uppercase() }
|
||||
}
|
||||
gamemodeBox.value = server.getProp("gamemode").replaceFirstChar { it.uppercase() }
|
||||
worldTypeBox.value = server.getProp("level-type").removePrefix("minecraft:")
|
||||
.split('_').joinToString(" ") { it.replaceFirstChar(Char::uppercaseChar)}
|
||||
worldTypeBox.value =
|
||||
server.getProp("level-type").removePrefix("minecraft:").split('_').joinToString(" ") {
|
||||
it.replaceFirstChar(Char::uppercaseChar)
|
||||
}
|
||||
worldNameField.text = server.getProp("level-name")
|
||||
seedField.text = server.getProp("level-seed")
|
||||
loading = false
|
||||
|
@ -373,7 +303,13 @@ class PrimaryController {
|
|||
|
||||
@FXML
|
||||
private fun onDefaults() {
|
||||
val res = CommonDialog("info", "Reset all settings?", "Reset settings to defaults?\nThere is NO GOING BACK!").show()
|
||||
val res =
|
||||
CommonDialog(
|
||||
"info",
|
||||
"Reset all settings?",
|
||||
"Reset settings to defaults?\nThere is NO GOING BACK!"
|
||||
)
|
||||
.show()
|
||||
if (res) {
|
||||
server.loadProps()
|
||||
applyProps()
|
||||
|
@ -387,7 +323,7 @@ class PrimaryController {
|
|||
val scene = Scene(FXMLLoader(App().javaClass.getResource("info.fxml")).load(), 398.0, 358.0)
|
||||
stage.icons.add(Image(App().javaClass.getResourceAsStream("app.png")))
|
||||
stage.setResizable(false)
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
stage.initModality(Modality.APPLICATION_MODAL)
|
||||
stage.title = "About ServerCraft"
|
||||
stage.scene = scene
|
||||
stage.show()
|
||||
|
@ -399,7 +335,7 @@ class PrimaryController {
|
|||
building = false
|
||||
statusBar.text = "Cancelling..."
|
||||
buildButton.isDisable = true
|
||||
return;
|
||||
return
|
||||
}
|
||||
building = true
|
||||
worldSettingsPane.isDisable = true
|
||||
|
@ -429,24 +365,28 @@ class PrimaryController {
|
|||
}
|
||||
|
||||
// download files
|
||||
val downloads = mapOf(
|
||||
"Java 20" to "https://download.java.net/java/GA/jdk20.0.1/b4887098932d415489976708ad6d1a4b/9/GPL/${javaFile}",
|
||||
"BuildTools" to "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar",
|
||||
)
|
||||
val destinations = mapOf (
|
||||
"Java 20" to directory + "ServerCraft" + File.separator + "Java" + File.separator,
|
||||
"BuildTools" to directory + "ServerCraft" + File.separator + "Spigot" + File.separator
|
||||
)
|
||||
val downloads =
|
||||
mapOf(
|
||||
"Java 20" to
|
||||
"https://download.java.net/java/GA/jdk20.0.1/b4887098932d415489976708ad6d1a4b/9/GPL/${javaFile}",
|
||||
"BuildTools" to
|
||||
"https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar",
|
||||
)
|
||||
val destinations =
|
||||
mapOf(
|
||||
"Java 20" to
|
||||
directory + "ServerCraft" + File.separator + "Java" + File.separator,
|
||||
"BuildTools" to
|
||||
directory + "ServerCraft" + File.separator + "Spigot" + File.separator
|
||||
)
|
||||
val spigotBuilt = File(destinations["BuildTools"]).exists()
|
||||
val javaExtracted = File(destinations["Java 20"] + "jdk-20.0.1").exists()
|
||||
destinations.forEach {
|
||||
File(it.value).mkdir()
|
||||
}
|
||||
destinations.forEach { File(it.value).mkdir() }
|
||||
downloads.forEach {
|
||||
if (it.key == "Java 20" && javaExtracted) {
|
||||
return@forEach
|
||||
}
|
||||
withContext(Dispatchers.JavaFx){
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
statusBar.text = "Downloading ${it.key}..."
|
||||
progressBar.progress = ProgressBar.INDETERMINATE_PROGRESS
|
||||
log("Downloading ${it.key} from ${it.value}\n")
|
||||
|
@ -455,15 +395,18 @@ class PrimaryController {
|
|||
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
|
||||
withContext(Dispatchers.JavaFx) {log("Progress: ${prog * 100}%\n")}
|
||||
// for whatever reason I need to print something to the screen in order for it to update
|
||||
// the progress bar
|
||||
withContext(Dispatchers.JavaFx) { log("Progress: ${prog * 100}%\n") }
|
||||
if (prog >= 0.01) {
|
||||
withContext(Dispatchers.JavaFx) {progressBar.progress = prog}
|
||||
withContext(Dispatchers.JavaFx) { progressBar.progress = prog }
|
||||
}
|
||||
if (!building) download.status = Download.Status.CANCELLED
|
||||
Thread.sleep(300)
|
||||
}
|
||||
withContext(Dispatchers.JavaFx) {log("Download of ${it.key} complete with status: ${download.status}\n")}
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
log("Download of ${it.key} complete with status: ${download.status}\n")
|
||||
}
|
||||
}
|
||||
|
||||
// extract java archive
|
||||
|
@ -473,18 +416,38 @@ class PrimaryController {
|
|||
statusBar.text = "Extracting Java archive..."
|
||||
log("Extracting Java archive to ${directory + "ServerCraft" + File.separator + "Java"}\n")
|
||||
}
|
||||
var stream = archiver.stream(File(directory + "ServerCraft" + File.separator + "Java" + File.separator + javaFile))
|
||||
var stream =
|
||||
archiver.stream(
|
||||
File(
|
||||
directory +
|
||||
"ServerCraft" +
|
||||
File.separator +
|
||||
"Java" +
|
||||
File.separator +
|
||||
javaFile
|
||||
)
|
||||
)
|
||||
val dest = File(directory + "ServerCraft" + File.separator + "Java")
|
||||
var entries = 0.0
|
||||
while(stream.getNextEntry() != null && building) {
|
||||
while (stream.getNextEntry() != null && building) {
|
||||
entries++
|
||||
}
|
||||
stream = archiver.stream(File(directory + "ServerCraft" + File.separator + "Java" + File.separator + javaFile))
|
||||
stream =
|
||||
archiver.stream(
|
||||
File(
|
||||
directory +
|
||||
"ServerCraft" +
|
||||
File.separator +
|
||||
"Java" +
|
||||
File.separator +
|
||||
javaFile
|
||||
)
|
||||
)
|
||||
var entry = stream.getNextEntry()
|
||||
var currentEntry = 0.0
|
||||
do {
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
progressBar.progress = currentEntry/entries
|
||||
progressBar.progress = currentEntry / entries
|
||||
log(entry.name + "\n")
|
||||
}
|
||||
entry.extract(dest)
|
||||
|
@ -498,7 +461,16 @@ class PrimaryController {
|
|||
progressBar.progress = ProgressBar.INDETERMINATE_PROGRESS
|
||||
statusBar.text = "Building Minecraft Server..."
|
||||
}
|
||||
val builder = ProcessBuilder("${directory}ServerCraft${File.separator}Java${File.separator}jdk-20.0.1${File.separator}bin${File.separator}java", "-jar", "BuildTools.jar", "--rev", "latest", "-o", ".." + File.separator + ".." + File.separator)
|
||||
val builder =
|
||||
ProcessBuilder(
|
||||
"${directory}ServerCraft${File.separator}Java${File.separator}jdk-20.0.1${File.separator}bin${File.separator}java",
|
||||
"-jar",
|
||||
"BuildTools.jar",
|
||||
"--rev",
|
||||
"latest",
|
||||
"-o",
|
||||
".." + File.separator + ".." + File.separator
|
||||
)
|
||||
builder.directory(File(directory + "ServerCraft" + File.separator + "Spigot"))
|
||||
val proc = builder.start()
|
||||
val reader = InputStreamReader(proc.inputStream)
|
||||
|
@ -509,40 +481,48 @@ class PrimaryController {
|
|||
if (!building) {
|
||||
proc.destroy()
|
||||
}
|
||||
withContext(Dispatchers.JavaFx) {log(cbuf.joinToString(separator=""))}
|
||||
withContext(Dispatchers.JavaFx) { log(cbuf.joinToString(separator = "")) }
|
||||
cbuf = CharArray(1000)
|
||||
reader.read(cbuf, 0, 1000)
|
||||
currentline++
|
||||
if (currentline > 15) {
|
||||
withContext(Dispatchers.JavaFx) {progressBar.progress = if (spigotBuilt) {currentline/1100.0} else {currentline/14122.0} }
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
progressBar.progress =
|
||||
if (spigotBuilt) {
|
||||
currentline / 1100.0
|
||||
} else {
|
||||
currentline / 14122.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cbuf = CharArray(1000)
|
||||
reader.read(cbuf, 0, 1000)
|
||||
withContext(Dispatchers.JavaFx) {log(cbuf.joinToString(separator=""))}
|
||||
withContext(Dispatchers.JavaFx) { log(cbuf.joinToString(separator = "")) }
|
||||
} catch (e: IOException) {
|
||||
withContext(Dispatchers.JavaFx) {log("Stream Closed\n")}
|
||||
withContext(Dispatchers.JavaFx) { log("Stream Closed\n") }
|
||||
}
|
||||
}
|
||||
|
||||
progressBar.isVisible = false
|
||||
findServerJar()
|
||||
withContext(Dispatchers.JavaFx){
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
worldSettingsPane.isDisable = false
|
||||
directoryPane.isDisable = false
|
||||
parentPane.isDisable = false
|
||||
defaultsButton.isDisable = false
|
||||
buildButton.text = "Build Server"
|
||||
buildButton.isDisable = false
|
||||
statusBar.text = if (building) {
|
||||
findServerJar()
|
||||
buildButton.text = "Rebuild Server"
|
||||
startButton.isDisable = false
|
||||
"Ready."
|
||||
} else {
|
||||
"Server build cancelled."
|
||||
}
|
||||
building = false;
|
||||
statusBar.text =
|
||||
if (building) {
|
||||
findServerJar()
|
||||
buildButton.text = "Rebuild Server"
|
||||
startButton.isDisable = false
|
||||
"Ready."
|
||||
} else {
|
||||
"Server build cancelled."
|
||||
}
|
||||
building = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -551,18 +531,19 @@ class PrimaryController {
|
|||
private fun onStart() {
|
||||
if (started) {
|
||||
killDialog.show()
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (!File(directory + "eula.txt").exists()) {
|
||||
val res = EulaDialog().show()
|
||||
if (res) {
|
||||
File(directory + "eula.txt").writeText("eula=true")
|
||||
} else {
|
||||
return;
|
||||
return
|
||||
}
|
||||
}
|
||||
started = true
|
||||
statusBar.text = "The Minecraft Server is now running. Shutdown the server to unlock the settings."
|
||||
statusBar.text =
|
||||
"The Minecraft Server is now running. Shutdown the server to unlock the settings."
|
||||
worldSettingsPane.isDisable = true
|
||||
directoryPane.isDisable = true
|
||||
parentPane.isDisable = true
|
||||
|
@ -571,7 +552,13 @@ class PrimaryController {
|
|||
startButton.text = "Kill Server"
|
||||
@Suppress("OPT_IN_USAGE")
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
val builder = ProcessBuilder("${directory}ServerCraft${File.separator}Java${File.separator}jdk-20.0.1${File.separator}bin${File.separator}java", "-Xmx${server.getProp("jvm-ram")}M", "-jar", "${server.jar}")
|
||||
val builder =
|
||||
ProcessBuilder(
|
||||
"${directory}ServerCraft${File.separator}Java${File.separator}jdk-20.0.1${File.separator}bin${File.separator}java",
|
||||
"-Xmx${server.getProp("jvm-ram")}M",
|
||||
"-jar",
|
||||
"${server.jar}"
|
||||
)
|
||||
builder.directory(File(directory))
|
||||
val proc = builder.start()
|
||||
val reader = InputStreamReader(proc.inputStream)
|
||||
|
@ -586,23 +573,24 @@ class PrimaryController {
|
|||
}
|
||||
proc.destroy()
|
||||
}
|
||||
withContext(Dispatchers.JavaFx) {log(cbuf.joinToString(separator=""))}
|
||||
withContext(Dispatchers.JavaFx) { log(cbuf.joinToString(separator = "")) }
|
||||
cbuf = CharArray(1000)
|
||||
reader.read(cbuf, 0, 1000)
|
||||
}
|
||||
cbuf = CharArray(1000)
|
||||
reader.read(cbuf, 0, 1000)
|
||||
withContext(Dispatchers.JavaFx) {log(cbuf.joinToString(separator=""))}
|
||||
withContext(Dispatchers.JavaFx) { log(cbuf.joinToString(separator = "")) }
|
||||
} catch (e: IOException) {
|
||||
withContext(Dispatchers.JavaFx) {log("Stream Closed\n")}
|
||||
withContext(Dispatchers.JavaFx) { log("Stream Closed\n") }
|
||||
}
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
statusBar.text = if (killDialog.result) {
|
||||
killDialog.result = false
|
||||
"Server killed."
|
||||
} else {
|
||||
"Server stopped."
|
||||
}
|
||||
statusBar.text =
|
||||
if (killDialog.result) {
|
||||
killDialog.result = false
|
||||
"Server killed."
|
||||
} else {
|
||||
"Server stopped."
|
||||
}
|
||||
worldSettingsPane.isDisable = false
|
||||
directoryPane.isDisable = false
|
||||
parentPane.isDisable = false
|
||||
|
@ -619,12 +607,11 @@ class PrimaryController {
|
|||
directory = dir
|
||||
// exit if doesn't exist for whatever reason
|
||||
if (!File(directory).isDirectory) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
// add system dir separator for cleaner code
|
||||
if (directory[directory.length-1] != File.separatorChar)
|
||||
directory += File.separatorChar
|
||||
if (directory[directory.length - 1] != File.separatorChar) directory += File.separatorChar
|
||||
|
||||
val hasDummy = File(directory + "ServerCraft").isDirectory
|
||||
val hasProperties = File(directory + File.separator + "server.properties").isFile
|
||||
|
@ -641,19 +628,27 @@ class PrimaryController {
|
|||
statusBar.text = "Server needs to be built before starting."
|
||||
} else if (!hasDummy && hasServer) {
|
||||
// server created externally
|
||||
val result = CommonDialog("warning", directory, "This server directory was not created by \nServerCraft. Errors may occur; copying\nthe world directories to a new folder may be\nsafer. Proceed anyway?").show()
|
||||
val result =
|
||||
CommonDialog(
|
||||
"warning",
|
||||
directory,
|
||||
"This server directory was not created by \nServerCraft. Errors may occur; copying\nthe world directories to a new folder may be\nsafer. Proceed anyway?"
|
||||
)
|
||||
.show()
|
||||
statusBar.text = "Ready."
|
||||
if (result) {
|
||||
startButton.isDisable = true
|
||||
File(directory + "ServerCraft").mkdir()
|
||||
buildButton.text = "Build Server"
|
||||
statusBar.text = "Server converted. Build the server to start."
|
||||
server.loadProps(dir, convert=true)
|
||||
server.loadProps(dir, convert = true)
|
||||
}
|
||||
return result
|
||||
} else {
|
||||
// assume clean directory
|
||||
val result = CommonDialog("info", directory, "There is no server in this directory.\nCreate one?").show()
|
||||
val result =
|
||||
CommonDialog("info", directory, "There is no server in this directory.\nCreate one?")
|
||||
.show()
|
||||
if (result) {
|
||||
File(directory + "ServerCraft").mkdir()
|
||||
startButton.isDisable = true
|
||||
|
@ -671,7 +666,7 @@ class PrimaryController {
|
|||
server.loadProps()
|
||||
}
|
||||
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
private fun findServerJar(): Boolean {
|
||||
|
@ -681,10 +676,7 @@ class PrimaryController {
|
|||
// patch number
|
||||
for (j in 15 downTo 0) {
|
||||
var spigotFile: String = ""
|
||||
if (j == 0)
|
||||
spigotFile += "spigot-1.$i.jar"
|
||||
else
|
||||
spigotFile += "spigot-1.$i.$j.jar";
|
||||
if (j == 0) spigotFile += "spigot-1.$i.jar" else spigotFile += "spigot-1.$i.$j.jar"
|
||||
|
||||
if (File(directory + spigotFile).isFile) {
|
||||
server.jar = directory + spigotFile
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package xyz.brysonsteck.ServerCraft.dialogs
|
||||
|
||||
import javafx.scene.control.Button
|
||||
import javafx.event.EventHandler
|
||||
import javafx.event.ActionEvent
|
||||
import javafx.event.EventHandler
|
||||
import javafx.scene.control.Button
|
||||
|
||||
class CommonDialog: Dialog {
|
||||
class CommonDialog : Dialog {
|
||||
override var type: String
|
||||
override var title: String
|
||||
override var msg: String
|
||||
|
@ -18,17 +18,18 @@ class CommonDialog: Dialog {
|
|||
this.msg = msg
|
||||
|
||||
noButton = Button("No")
|
||||
noButton.onAction = EventHandler<ActionEvent>() {
|
||||
result = false
|
||||
dialog.hide()
|
||||
}
|
||||
noButton.onAction =
|
||||
EventHandler<ActionEvent>() {
|
||||
result = false
|
||||
dialog.hide()
|
||||
}
|
||||
yesButton = Button("Yes")
|
||||
yesButton.onAction = EventHandler<ActionEvent>() {
|
||||
result = true
|
||||
dialog.hide()
|
||||
}
|
||||
yesButton.onAction =
|
||||
EventHandler<ActionEvent>() {
|
||||
result = true
|
||||
dialog.hide()
|
||||
}
|
||||
yesButton.isDefaultButton = true
|
||||
neutralButton = null
|
||||
}
|
||||
|
||||
}
|
|
@ -1,17 +1,15 @@
|
|||
package xyz.brysonsteck.ServerCraft.dialogs
|
||||
|
||||
import javafx.geometry.Insets
|
||||
import javafx.scene.Scene
|
||||
import javafx.scene.control.Button
|
||||
import javafx.scene.control.ButtonBar
|
||||
import javafx.scene.control.Label
|
||||
import javafx.scene.image.Image
|
||||
import javafx.scene.image.ImageView
|
||||
import javafx.scene.layout.Pane
|
||||
import javafx.scene.Scene
|
||||
import javafx.stage.Modality
|
||||
import javafx.stage.Stage
|
||||
import javafx.geometry.Insets
|
||||
import javafx.event.EventHandler
|
||||
import javafx.event.ActionEvent
|
||||
import xyz.brysonsteck.ServerCraft.App
|
||||
|
||||
abstract class Dialog {
|
||||
|
@ -33,7 +31,7 @@ abstract class Dialog {
|
|||
val icon = Image("$resources")
|
||||
dialog.icons.add(Image(App().javaClass.getResourceAsStream("app.png")))
|
||||
dialog.setResizable(false)
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.initModality(Modality.APPLICATION_MODAL)
|
||||
dialog.title = title
|
||||
val imagePane = Pane()
|
||||
imagePane.layoutX = 14.0
|
||||
|
@ -64,14 +62,13 @@ abstract class Dialog {
|
|||
ButtonBar.setButtonData(neutralButton, ButtonBar.ButtonData.LEFT)
|
||||
buttonBar.buttons.add(neutralButton)
|
||||
}
|
||||
val dialogScene = Scene(scenePane, 400.0, 150.0);
|
||||
dialog.setScene(dialogScene);
|
||||
val dialogScene = Scene(scenePane, 400.0, 150.0)
|
||||
dialog.setScene(dialogScene)
|
||||
if (hold) {
|
||||
dialog.showAndWait();
|
||||
dialog.showAndWait()
|
||||
} else {
|
||||
dialog.show();
|
||||
dialog.show()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
package xyz.brysonsteck.ServerCraft.dialogs
|
||||
|
||||
import xyz.brysonsteck.ServerCraft.dialogs.Dialog
|
||||
import javafx.scene.control.Button
|
||||
import javafx.event.EventHandler
|
||||
import javafx.event.ActionEvent
|
||||
import java.awt.Desktop
|
||||
import java.net.URI
|
||||
import javafx.event.ActionEvent
|
||||
import javafx.event.EventHandler
|
||||
import javafx.scene.control.Button
|
||||
|
||||
class EulaDialog: Dialog {
|
||||
class EulaDialog : Dialog {
|
||||
override val type: String
|
||||
override val title: String
|
||||
override val msg: String
|
||||
|
@ -18,38 +17,40 @@ class EulaDialog: Dialog {
|
|||
constructor() {
|
||||
type = "warning"
|
||||
title = "Minecraft End User License Agreement (EULA)"
|
||||
msg = "Do you agree to the terms of the Minecraft End User License Agreement?"
|
||||
msg = "Do you agree to the terms of the Minecraft\nEnd User License Agreement?"
|
||||
|
||||
noButton = Button("I Disagree")
|
||||
noButton.onAction = EventHandler<ActionEvent>() {
|
||||
result = false
|
||||
dialog.hide()
|
||||
}
|
||||
noButton.onAction =
|
||||
EventHandler<ActionEvent>() {
|
||||
result = false
|
||||
dialog.hide()
|
||||
}
|
||||
noButton.isDefaultButton = true
|
||||
yesButton = Button("I Agree")
|
||||
yesButton.onAction = EventHandler<ActionEvent>() {
|
||||
result = true
|
||||
dialog.hide()
|
||||
}
|
||||
yesButton.onAction =
|
||||
EventHandler<ActionEvent>() {
|
||||
result = true
|
||||
dialog.hide()
|
||||
}
|
||||
neutralButton = Button("View EULA")
|
||||
neutralButton.onAction = EventHandler<ActionEvent>() {
|
||||
val desktop = Desktop.getDesktop()
|
||||
if (desktop.isSupported(Desktop.Action.BROWSE)) {
|
||||
// most likely running on Windows or macOS
|
||||
try {
|
||||
desktop.browse(URI("https://account.mojang.com/documents/minecraft_eula"))
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
}
|
||||
} else {
|
||||
// assume running on linux
|
||||
try {
|
||||
Runtime.getRuntime().exec("xdg-open https://account.mojang.com/documents/minecraft_eula");
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
neutralButton.onAction =
|
||||
EventHandler<ActionEvent>() {
|
||||
val desktop = Desktop.getDesktop()
|
||||
if (desktop.isSupported(Desktop.Action.BROWSE)) {
|
||||
// most likely running on Windows or macOS
|
||||
try {
|
||||
desktop.browse(URI("https://www.minecraft.net/en-us/eula"))
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
}
|
||||
} else {
|
||||
// assume running on linux
|
||||
try {
|
||||
Runtime.getRuntime().exec("xdg-open https://www.minecraft.net/en-us/eula")
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package xyz.brysonsteck.ServerCraft.dialogs
|
||||
|
||||
import javafx.scene.control.Button
|
||||
import javafx.event.EventHandler
|
||||
import javafx.event.ActionEvent
|
||||
import javafx.event.EventHandler
|
||||
import javafx.scene.control.Button
|
||||
|
||||
class KillDialog: Dialog {
|
||||
class KillDialog : Dialog {
|
||||
override val type: String
|
||||
override val title: String
|
||||
override val msg: String
|
||||
|
@ -15,19 +15,22 @@ class KillDialog: Dialog {
|
|||
constructor() {
|
||||
type = "warning"
|
||||
title = "Server is still running!"
|
||||
msg = "You should only kill the server if absolutely necessary, i.e. not being responsive after long periods of time. Data loss may occur. Continue anyway?"
|
||||
msg =
|
||||
"You should only kill the server if absolutely necessary, i.e. not being responsive after long periods of time. Data loss may occur. Continue anyway?"
|
||||
hold = false
|
||||
|
||||
noButton = Button("No")
|
||||
noButton.onAction = EventHandler<ActionEvent>() {
|
||||
result = false
|
||||
dialog.hide()
|
||||
}
|
||||
noButton.onAction =
|
||||
EventHandler<ActionEvent>() {
|
||||
result = false
|
||||
dialog.hide()
|
||||
}
|
||||
yesButton = Button("Yes")
|
||||
yesButton.onAction = EventHandler<ActionEvent>() {
|
||||
result = true
|
||||
dialog.hide()
|
||||
}
|
||||
yesButton.onAction =
|
||||
EventHandler<ActionEvent>() {
|
||||
result = true
|
||||
dialog.hide()
|
||||
}
|
||||
yesButton.isDefaultButton = true
|
||||
neutralButton = null
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package xyz.brysonsteck.ServerCraft.server
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.io.*
|
||||
import java.net.*
|
||||
import java.util.*
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
||||
class Download: Runnable {
|
||||
class Download : Runnable {
|
||||
public enum class Status {
|
||||
DOWNLOADING, PAUSED, COMPLETE, CANCELLED, ERROR
|
||||
DOWNLOADING,
|
||||
PAUSED,
|
||||
COMPLETE,
|
||||
CANCELLED,
|
||||
ERROR
|
||||
}
|
||||
public var size: Int
|
||||
public var downloaded: Int
|
||||
|
@ -19,7 +23,7 @@ class Download: Runnable {
|
|||
private var url: URL
|
||||
private var dir: String
|
||||
|
||||
constructor (url: URL, dir: String) {
|
||||
constructor(url: URL, dir: String) {
|
||||
this.url = url
|
||||
this.dir = dir
|
||||
size = -1
|
||||
|
@ -44,13 +48,13 @@ class Download: Runnable {
|
|||
|
||||
try {
|
||||
// Open connection to URL.
|
||||
var connection = url.openConnection() as HttpsURLConnection;
|
||||
var connection = url.openConnection() as HttpsURLConnection
|
||||
|
||||
// Specify what portion of file to download.
|
||||
connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
|
||||
connection.setRequestProperty("Range", "bytes=" + downloaded + "-")
|
||||
|
||||
// Connect to server.
|
||||
connection.connect();
|
||||
connection.connect()
|
||||
|
||||
// Make sure response code is in the 200 range.
|
||||
if (connection.responseCode / 100 != 2) {
|
||||
|
@ -58,64 +62,63 @@ class Download: Runnable {
|
|||
}
|
||||
|
||||
// Check for valid content length.
|
||||
contentLength = connection.getContentLength();
|
||||
contentLength = connection.getContentLength()
|
||||
if (contentLength < 1) {
|
||||
status = Status.ERROR
|
||||
}
|
||||
|
||||
/* Set the size for this download if it
|
||||
hasn't been already set. */
|
||||
hasn't been already set. */
|
||||
if (size == -1) {
|
||||
size = contentLength;
|
||||
size = contentLength
|
||||
}
|
||||
|
||||
// Open file and seek to the end of it.
|
||||
file = RandomAccessFile(dir + getFilename(url), "rw");
|
||||
file.seek(downloaded.toLong());
|
||||
file = RandomAccessFile(dir + getFilename(url), "rw")
|
||||
file.seek(downloaded.toLong())
|
||||
|
||||
stream = connection.getInputStream();
|
||||
stream = connection.getInputStream()
|
||||
while (status == Status.DOWNLOADING) {
|
||||
/* Size buffer according to how much of the
|
||||
file is left to download. */
|
||||
val buffer: ByteArray;
|
||||
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);
|
||||
buffer = ByteArray(size - downloaded)
|
||||
}
|
||||
|
||||
// Read from server into buffer.
|
||||
val read = stream.read(buffer);
|
||||
if (read == -1)
|
||||
break;
|
||||
val read = stream.read(buffer)
|
||||
if (read == -1) break
|
||||
|
||||
// Write buffer to file.
|
||||
file.write(buffer, 0, read);
|
||||
downloaded += read;
|
||||
file.write(buffer, 0, read)
|
||||
downloaded += read
|
||||
}
|
||||
|
||||
/* Change status to complete if this point was
|
||||
reached because downloading has finished. */
|
||||
reached because downloading has finished. */
|
||||
if (status == Status.DOWNLOADING) {
|
||||
status = Status.COMPLETE;
|
||||
status = Status.COMPLETE
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
status = Status.ERROR
|
||||
} finally {
|
||||
// Close file.
|
||||
if (file != null) {
|
||||
try {
|
||||
file.close();
|
||||
} catch (e: Exception) {}
|
||||
}
|
||||
// Close file.
|
||||
if (file != null) {
|
||||
try {
|
||||
file.close()
|
||||
} catch (e: Exception) {}
|
||||
}
|
||||
|
||||
// Close connection to server.
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (e: Exception) {}
|
||||
}
|
||||
// Close connection to server.
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close()
|
||||
} catch (e: Exception) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package xyz.brysonsteck.ServerCraft.server
|
||||
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.util.Properties
|
||||
|
||||
|
@ -41,19 +40,34 @@ public class Server {
|
|||
var ins = File(dir + File.separator + "server.properties").inputStream()
|
||||
props.load(ins)
|
||||
try {
|
||||
ins = File(dir + File.separator + "ServerCraft" + File.separator + "ServerCraft.properties").inputStream()
|
||||
ins =
|
||||
File(dir + File.separator + "ServerCraft" + File.separator + "ServerCraft.properties")
|
||||
.inputStream()
|
||||
props.load(ins)
|
||||
} catch (e: FileNotFoundException) {
|
||||
if (convert) {
|
||||
// create the file in question, as this is an external server being converted into a ServerCraft managed one
|
||||
File(dir + File.separator + "ServerCraft" + File.separator + "ServerCraft.properties").createNewFile()
|
||||
// create the file in question, as this is an external server being converted into a
|
||||
// ServerCraft managed one
|
||||
File(dir + File.separator + "ServerCraft" + File.separator + "ServerCraft.properties")
|
||||
.createNewFile()
|
||||
// also apply app-specific properties
|
||||
props.setProperty("jvm-ram", 1024.toString())
|
||||
// then write to file
|
||||
val temp = Properties()
|
||||
val outs = File(dir + File.separator + "ServerCraft" + File.separator + "ServerCraft.properties").outputStream()
|
||||
val outs =
|
||||
File(
|
||||
dir +
|
||||
File.separator +
|
||||
"ServerCraft" +
|
||||
File.separator +
|
||||
"ServerCraft.properties"
|
||||
)
|
||||
.outputStream()
|
||||
temp.setProperty("jvm-ram", props.getProperty("jvm-ram"))
|
||||
temp.store(outs, "ServerCraft settings backup\nSometimes, Minecraft will completely overwrite the server.properties file,\ncompletely destroying these app-specific settings. This file backs up these settings\njust in case. :)\nhttps://codeberg.org/brysonsteck/ServerCraft")
|
||||
temp.store(
|
||||
outs,
|
||||
"ServerCraft settings backup\nSometimes, Minecraft will completely overwrite the server.properties file,\ncompletely destroying these app-specific settings. This file backs up these settings\njust in case. :)\nhttps://codeberg.org/brysonsteck/ServerCraft"
|
||||
)
|
||||
} else {
|
||||
println(e)
|
||||
}
|
||||
|
@ -62,11 +76,19 @@ public class Server {
|
|||
|
||||
private fun writeProps() {
|
||||
var outs = File(dir + File.separator + "server.properties").outputStream()
|
||||
props.store(outs, "Minecraft server properties\nCreated with ServerCraft: https://codeberg.org/brysonsteck/ServerCraft")
|
||||
props.store(
|
||||
outs,
|
||||
"Minecraft server properties\nCreated with ServerCraft: https://codeberg.org/brysonsteck/ServerCraft"
|
||||
)
|
||||
val temp = Properties()
|
||||
outs = File(dir + File.separator + "ServerCraft" + File.separator + "ServerCraft.properties").outputStream()
|
||||
outs =
|
||||
File(dir + File.separator + "ServerCraft" + File.separator + "ServerCraft.properties")
|
||||
.outputStream()
|
||||
temp.setProperty("jvm-ram", props.getProperty("jvm-ram"))
|
||||
temp.store(outs, "ServerCraft settings backup\nSometimes, Minecraft will completely overwrite the server.properties file,\ncompletely destroying these app-specific settings. This file backs up these settings\njust in case. :)\nhttps://codeberg.org/brysonsteck/ServerCraft")
|
||||
temp.store(
|
||||
outs,
|
||||
"ServerCraft settings backup\nSometimes, Minecraft will completely overwrite the server.properties file,\ncompletely destroying these app-specific settings. This file backs up these settings\njust in case. :)\nhttps://codeberg.org/brysonsteck/ServerCraft"
|
||||
)
|
||||
}
|
||||
|
||||
public fun getProp(prop: String): String {
|
||||
|
@ -77,5 +99,4 @@ public class Server {
|
|||
props.setProperty(key, value.toString())
|
||||
writeProps()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
.root{
|
||||
-fx-font-size: 11pt;
|
||||
-fx-font-family: "Inter";
|
||||
}
|
|
@ -8,379 +8,374 @@
|
|||
<?import javafx.scene.control.ContextMenu?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.MenuItem?>
|
||||
<?import javafx.scene.control.ProgressBar?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
<?import javafx.scene.control.Spinner?>
|
||||
<?import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.control.TitledPane?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<Pane fx:id="primary" maxHeight="873.0" maxWidth="963.0" minHeight="713.0" minWidth="963.0" prefHeight="873.0" prefWidth="963.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.brysonsteck.ServerCraft.controllers.PrimaryController">
|
||||
|
||||
<AnchorPane fx:id="primary" minHeight="200.0" minWidth="200.0" prefHeight="633.0" prefWidth="1054.0" xmlns="http://javafx.com/javafx/23.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.brysonsteck.ServerCraft.controllers.PrimaryController">
|
||||
<children>
|
||||
<HBox fx:id="directoryPane" prefHeight="39.0" prefWidth="963.0">
|
||||
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<Button id="openFile" fx:id="chooseDirectoryButton" lineSpacing="10.0" mnemonicParsing="false" onAction="#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:" HBox.hgrow="ALWAYS">
|
||||
<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" text="world">
|
||||
<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" promptText="Leave empty for random seed" HBox.hgrow="ALWAYS">
|
||||
<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:" HBox.hgrow="ALWAYS">
|
||||
<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" editable="true" prefWidth="95.0">
|
||||
<HBox.margin>
|
||||
<Insets top="2.0" />
|
||||
</HBox.margin>
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="25565" max="60000" min="20000" />
|
||||
</valueFactory>
|
||||
</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" onAction="#onCheckboxClick" text="Allow Flight" />
|
||||
<CheckBox fx:id="netherCheckbox" layoutX="14.0" layoutY="42.0" mnemonicParsing="false" onAction="#onCheckboxClick" selected="true" text="Allow The Nether" />
|
||||
<CheckBox fx:id="structuresCheckbox" alignment="TOP_LEFT" layoutX="14.0" layoutY="70.0" mnemonicParsing="false" onAction="#onCheckboxClick" selected="true" text="Generate Structures (such as villages and strongholds)" />
|
||||
<CheckBox fx:id="pvpCheckbox" layoutX="14.0" layoutY="109.0" mnemonicParsing="false" onAction="#onCheckboxClick" selected="true" text="Allow PvP" />
|
||||
<CheckBox fx:id="whitelistCheckbox" alignment="TOP_LEFT" layoutX="14.0" layoutY="138.0" mnemonicParsing="false" onAction="#onCheckboxClick" text="Enable Whitelist (Only users you specify can join)" />
|
||||
<HBox layoutX="6.0" layoutY="174.0">
|
||||
<children>
|
||||
<Label text="Maximum Players:" HBox.hgrow="ALWAYS">
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="maxPlayerSpinner" editable="true" prefHeight="23.0" prefWidth="99.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="20" max="1000" min="0" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="6.0" layoutY="207.0">
|
||||
<children>
|
||||
<Label text="Maximum World Size (in blocks):" HBox.hgrow="ALWAYS">
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="maxSizeSpinner" editable="true" prefHeight="23.0" prefWidth="155.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="29999984" max="29999984" min="1" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane fx:id="advancedPane" expanded="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" onAction="#onCheckboxClick" text="Enable Command Blocks" />
|
||||
<CheckBox fx:id="playerCountCheckbox" layoutX="14.0" layoutY="41.0" mnemonicParsing="false" onAction="#onCheckboxClick" text="Hide Online Player Count" />
|
||||
<HBox layoutX="7.0" layoutY="65.0">
|
||||
<children>
|
||||
<Label ellipsisString="" text="Server Memory in MB:" textOverrun="CLIP" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="memorySpinner" editable="true" prefHeight="23.0" prefWidth="99.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="1024" max="65536" min="512" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="7.0" layoutY="96.0">
|
||||
<children>
|
||||
<Label text="Spawn Protection Radius:" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="spawnSpinner" editable="true" prefHeight="23.0" prefWidth="99.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="16" max="29999984" min="0" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="7.0" layoutY="127.0">
|
||||
<children>
|
||||
<Label text="Simulation Distance:" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="simulationSpinner" editable="true" prefWidth="80.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="10" max="40" min="0" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="7.0" layoutY="160.0">
|
||||
<children>
|
||||
<Label text="Render Distance:" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="renderSpinner" editable="true" prefWidth="80.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="10" max="40" min="2" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="7.0" layoutY="192.0">
|
||||
<children>
|
||||
<Label text="Maximum Tick Time (in milliseconds):" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="maxTickSpinner" editable="true">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="60000" max="180000" min="10000" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
</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>
|
||||
</children>
|
||||
</Pane>
|
||||
<ButtonBar fx:id="buttonBar" buttonOrder="L+R" layoutY="635.0" prefHeight="40.0" prefWidth="963.0">
|
||||
<buttons>
|
||||
<Button fx:id="infoButton" mnemonicParsing="false" onAction="#onInfo" text="About ServerCraft" ButtonBar.buttonData="LEFT" />
|
||||
<Button fx:id="defaultsButton" disable="true" mnemonicParsing="false" onAction="#onDefaults" text="Reset to Defaults" ButtonBar.buttonData="LEFT" />
|
||||
<Button fx:id="buildButton" disable="true" mnemonicParsing="false" onAction="#onBuild" text="Build Server" ButtonBar.buttonData="RIGHT" />
|
||||
<Button fx:id="startButton" defaultButton="true" disable="true" mnemonicParsing="false" onAction="#onStart" prefWidth="120.0" text="Start Server" ButtonBar.buttonData="RIGHT" />
|
||||
</buttons>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</ButtonBar>
|
||||
<Pane layoutY="680.0" prefHeight="196.0" prefWidth="963.0" style="-fx-background-color: ddd;">
|
||||
<children>
|
||||
<HBox prefWidth="963.0">
|
||||
<HBox fx:id="directoryPane" minHeight="-Infinity" VBox.vgrow="NEVER">
|
||||
<children>
|
||||
<Label text="Status:">
|
||||
<Button id="openFile" fx:id="chooseDirectoryButton" lineSpacing="10.0" mnemonicParsing="false" onAction="#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 maxHeight="1.7976931348623157E308" orientation="VERTICAL">
|
||||
<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 fx:id="statusBar" text="Ready.">
|
||||
<Label id="currentFilename" fx:id="currentDirectoryLabel" text="<NONE>">
|
||||
<HBox.margin>
|
||||
<Insets left="5.0" />
|
||||
<Insets bottom="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<ProgressBar fx:id="progressBar" prefWidth="400.0" visible="false">
|
||||
<HBox.margin>
|
||||
<Insets left="10.0" />
|
||||
</HBox.margin>
|
||||
</ProgressBar>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="9.0" left="9.0" right="9.0" top="9.0" />
|
||||
</padding>
|
||||
</HBox>
|
||||
<ImageView fx:id="dropDownIcon" fitHeight="66.0" fitWidth="39.0" layoutX="923.0" layoutY="-3.0" onMouseClicked="#onToggleConsole" pickOnBounds="true" preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@icons/arrow_down.png" />
|
||||
</image>
|
||||
</ImageView>
|
||||
<ScrollPane fx:id="scrollPane" layoutY="34.0" prefHeight="162.0" prefWidth="963.0" vbarPolicy="ALWAYS">
|
||||
<padding>
|
||||
<Insets bottom="7.0" left="7.0" right="7.0" top="7.0" />
|
||||
</padding>
|
||||
<content>
|
||||
<Label fx:id="console" prefWidth="935.0" text="Console Output: " wrapText="true">
|
||||
</HBox>
|
||||
<HBox fx:id="worldSettingsPane" disable="true" minHeight="-Infinity" prefHeight="43.0" prefWidth="964.0">
|
||||
<padding>
|
||||
<Insets bottom="7.0" left="7.0" right="7.0" top="7.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<Label text="World Name:" HBox.hgrow="ALWAYS">
|
||||
<font>
|
||||
<Font name="Monospaced Regular" size="13.0" />
|
||||
<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>
|
||||
</content>
|
||||
</ScrollPane>
|
||||
<TextField fx:id="worldNameField" text="world">
|
||||
<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 prefHeight="0.0" 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" promptText="Leave empty for random seed" HBox.hgrow="ALWAYS">
|
||||
<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:" HBox.hgrow="ALWAYS">
|
||||
<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" editable="true" prefWidth="95.0">
|
||||
<HBox.margin>
|
||||
<Insets top="2.0" />
|
||||
</HBox.margin>
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="25565" max="60000" min="20000" />
|
||||
</valueFactory>
|
||||
</Spinner>
|
||||
</children>
|
||||
<opaqueInsets>
|
||||
<Insets bottom="3.0" />
|
||||
</opaqueInsets>
|
||||
</HBox>
|
||||
<GridPane fx:id="parentPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" VBox.vgrow="ALWAYS">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints halignment="CENTER" hgrow="NEVER" minWidth="10.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="317.0" minWidth="10.0" prefWidth="177.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<VBox prefHeight="505.0" prefWidth="584.0" GridPane.hgrow="ALWAYS">
|
||||
<children>
|
||||
<TitledPane fx:id="settingsPane" animated="false" collapsible="false" prefHeight="273.0" prefWidth="627.0" text="Server Settings">
|
||||
<content>
|
||||
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
|
||||
<children>
|
||||
<CheckBox fx:id="flightCheckbox" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onAction="#onCheckboxClick" text="Allow Flight" />
|
||||
<CheckBox fx:id="netherCheckbox" layoutX="14.0" layoutY="42.0" mnemonicParsing="false" onAction="#onCheckboxClick" selected="true" text="Allow The Nether" />
|
||||
<CheckBox fx:id="structuresCheckbox" alignment="TOP_LEFT" layoutX="14.0" layoutY="70.0" mnemonicParsing="false" onAction="#onCheckboxClick" selected="true" text="Generate Structures (such as villages and strongholds)" />
|
||||
<CheckBox fx:id="pvpCheckbox" layoutX="14.0" layoutY="109.0" mnemonicParsing="false" onAction="#onCheckboxClick" selected="true" text="Allow PvP" />
|
||||
<CheckBox fx:id="whitelistCheckbox" alignment="TOP_LEFT" layoutX="14.0" layoutY="138.0" mnemonicParsing="false" onAction="#onCheckboxClick" text="Enable Whitelist (Only users you specify can join)" />
|
||||
<HBox layoutX="6.0" layoutY="174.0">
|
||||
<children>
|
||||
<Label text="Maximum Players:" HBox.hgrow="ALWAYS">
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="maxPlayerSpinner" editable="true" prefHeight="23.0" prefWidth="99.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="20" max="1000" min="0" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="6.0" layoutY="207.0">
|
||||
<children>
|
||||
<Label text="Maximum World Size (in blocks):" HBox.hgrow="ALWAYS">
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="maxSizeSpinner" editable="true" prefHeight="23.0" prefWidth="155.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="29999984" max="29999984" min="1" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane fx:id="advancedPane" expanded="false" 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" onAction="#onCheckboxClick" text="Enable Command Blocks" />
|
||||
<CheckBox fx:id="playerCountCheckbox" layoutX="14.0" layoutY="41.0" mnemonicParsing="false" onAction="#onCheckboxClick" text="Hide Online Player Count" />
|
||||
<HBox layoutX="7.0" layoutY="65.0">
|
||||
<children>
|
||||
<Label ellipsisString="" text="Server Memory in MB:" textOverrun="CLIP" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="memorySpinner" editable="true" prefHeight="23.0" prefWidth="99.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="1024" max="65536" min="512" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="7.0" layoutY="96.0">
|
||||
<children>
|
||||
<Label text="Spawn Protection Radius:" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="spawnSpinner" editable="true" prefHeight="23.0" prefWidth="99.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="16" max="29999984" min="0" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="7.0" layoutY="127.0">
|
||||
<children>
|
||||
<Label text="Simulation Distance:" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="simulationSpinner" editable="true" prefWidth="80.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="10" max="40" min="0" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="7.0" layoutY="160.0">
|
||||
<children>
|
||||
<Label text="Render Distance:" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="renderSpinner" editable="true" prefWidth="80.0">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="10" max="40" min="2" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
<HBox layoutX="7.0" layoutY="192.0">
|
||||
<children>
|
||||
<Label text="Maximum Tick Time (in milliseconds):" HBox.hgrow="ALWAYS">
|
||||
<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>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<Spinner fx:id="maxTickSpinner" editable="true">
|
||||
<valueFactory>
|
||||
<SpinnerValueFactory.IntegerSpinnerValueFactory amountToStepBy="1" initialValue="60000" max="180000" min="10000" />
|
||||
</valueFactory>
|
||||
<HBox.margin>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</HBox.margin>
|
||||
</Spinner>
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
<padding>
|
||||
<Insets top="7.0" />
|
||||
</padding>
|
||||
</TitledPane>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="7.0" left="7.0" right="7.0" top="7.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
<VBox GridPane.columnIndex="1" GridPane.hgrow="ALWAYS">
|
||||
<children>
|
||||
<TitledPane fx:id="difficultyPane" animated="false" collapsible="false" text="Difficulty" VBox.vgrow="NEVER">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0">
|
||||
<children>
|
||||
<ChoiceBox fx:id="difficultyBox" layoutX="14.0" layoutY="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<contextMenu>
|
||||
<ContextMenu>
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" />
|
||||
</items>
|
||||
</ContextMenu>
|
||||
</contextMenu>
|
||||
</ChoiceBox>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</TitledPane>
|
||||
<TitledPane fx:id="gamemodePane" animated="false" collapsible="false" text="Gamemode" VBox.vgrow="NEVER">
|
||||
<content>
|
||||
<AnchorPane>
|
||||
<children>
|
||||
<ChoiceBox fx:id="gamemodeBox" layoutX="14.0" layoutY="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
<padding>
|
||||
<Insets top="7.0" />
|
||||
</padding>
|
||||
</TitledPane>
|
||||
<TitledPane fx:id="worldTypePane" animated="false" collapsible="false" text="World Type">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0">
|
||||
<children>
|
||||
<ChoiceBox fx:id="worldTypeBox" layoutX="14.0" layoutY="14.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
<padding>
|
||||
<Insets top="7.0" />
|
||||
</padding>
|
||||
</TitledPane>
|
||||
</children>
|
||||
<GridPane.margin>
|
||||
<Insets bottom="7.0" left="7.0" right="7.0" top="7.0" />
|
||||
</GridPane.margin>
|
||||
</VBox>
|
||||
</children>
|
||||
</GridPane>
|
||||
<HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" VBox.vgrow="NEVER">
|
||||
<children>
|
||||
<ButtonBar fx:id="buttonBar" buttonMinWidth="75.0" buttonOrder="L+R" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" HBox.hgrow="ALWAYS">
|
||||
<buttons>
|
||||
<Button fx:id="infoButton" mnemonicParsing="false" onAction="#onInfo" text="About ServerCraft" ButtonBar.buttonData="LEFT" />
|
||||
<Button fx:id="defaultsButton" disable="true" mnemonicParsing="false" onAction="#onDefaults" text="Reset to Defaults" ButtonBar.buttonData="LEFT" />
|
||||
<Button fx:id="buildButton" disable="true" mnemonicParsing="false" onAction="#onBuild" text="Build Server" ButtonBar.buttonData="RIGHT" />
|
||||
<Button fx:id="startButton" defaultButton="true" disable="true" mnemonicParsing="false" onAction="#onStart" prefWidth="120.0" text="Start Server" ButtonBar.buttonData="RIGHT" />
|
||||
</buttons>
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</ButtonBar>
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
</Pane>
|
||||
</VBox>
|
||||
</children>
|
||||
</Pane>
|
||||
</AnchorPane>
|
||||
|
|
Loading…
Add table
Reference in a new issue