implemented properties, console, and logging system
This commit is contained in:
parent
9b200a05ef
commit
49311129e9
7 changed files with 299 additions and 76 deletions
|
@ -89,6 +89,7 @@ task pack(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: bu
|
|||
organizationUrl = "https://brysonsteck.xyz"
|
||||
organizationEmail = "me@brysonsteck.xyz"
|
||||
url = "https://codeberg.org/brysonsteck/ServerCraft"
|
||||
additionalModules = [ "jdk.crypto.ec" ]
|
||||
|
||||
linuxConfig {
|
||||
pngFile = file('src/main/resources/icon.png')
|
||||
|
@ -113,7 +114,6 @@ task pack(type: io.github.fvarrui.javapackager.gradle.PackageTask, dependsOn: bu
|
|||
}
|
||||
}
|
||||
|
||||
// tasks.register('fixAppImageIcon', Copy) {
|
||||
build.doLast {
|
||||
if (OperatingSystem.current().isLinux()) {
|
||||
exec {
|
||||
|
|
|
@ -32,6 +32,7 @@ import javafx.scene.control.ButtonBar
|
|||
import javafx.scene.control.CheckBox
|
||||
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
|
||||
|
@ -50,6 +51,7 @@ import javafx.stage.DirectoryChooser
|
|||
import javafx.stage.Modality
|
||||
import javafx.stage.Stage
|
||||
import javafx.event.EventHandler
|
||||
import javafx.event.ActionEvent
|
||||
import org.rauschig.jarchivelib.*
|
||||
|
||||
import xyz.brysonsteck.ServerCraft.server.Server
|
||||
|
@ -57,6 +59,8 @@ import xyz.brysonsteck.ServerCraft.server.Download
|
|||
import xyz.brysonsteck.ServerCraft.App
|
||||
|
||||
class PrimaryController {
|
||||
@FXML
|
||||
lateinit private var primary: Pane
|
||||
@FXML
|
||||
lateinit private var currentDirectoryLabel: Label
|
||||
@FXML
|
||||
|
@ -94,7 +98,7 @@ class PrimaryController {
|
|||
@FXML
|
||||
lateinit private var playerCountCheckbox: CheckBox
|
||||
@FXML
|
||||
lateinit private var maxPlayersSpinner: Spinner<kotlin.Int>
|
||||
lateinit private var maxPlayerSpinner: Spinner<kotlin.Int>
|
||||
@FXML
|
||||
lateinit private var maxSizeSpinner: Spinner<kotlin.Int>
|
||||
@FXML
|
||||
|
@ -117,15 +121,29 @@ class PrimaryController {
|
|||
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
|
||||
private var building = false
|
||||
private var directory = ""
|
||||
private var asyncResult = false
|
||||
private var started = false
|
||||
private var loading = false
|
||||
private var showingConsole = false
|
||||
|
||||
private fun log(str: String) {
|
||||
console.text = console.text + str + "\n"
|
||||
println(str)
|
||||
}
|
||||
|
||||
@FXML
|
||||
public fun initialize() {
|
||||
scrollPane.vvalueProperty().bind(console.heightProperty());
|
||||
difficultyBox.items = FXCollections.observableArrayList(
|
||||
"Peaceful",
|
||||
"Easy",
|
||||
|
@ -135,7 +153,9 @@ class PrimaryController {
|
|||
)
|
||||
difficultyBox.value = "Normal"
|
||||
difficultyBox.selectionModel.selectedIndexProperty().addListener { _, _, new ->
|
||||
onChoiceBoxChange("difficulty", difficultyBox.items[new as Int])
|
||||
if (!loading) {
|
||||
onPropChange("difficulty", difficultyBox.items[new as Int])
|
||||
}
|
||||
}
|
||||
gamemodeBox.items = FXCollections.observableArrayList(
|
||||
"Survival",
|
||||
|
@ -145,7 +165,9 @@ class PrimaryController {
|
|||
)
|
||||
gamemodeBox.value = "Survival"
|
||||
gamemodeBox.selectionModel.selectedIndexProperty().addListener { _, _, new ->
|
||||
onChoiceBoxChange("gamemode", gamemodeBox.items[new as Int])
|
||||
if (!loading) {
|
||||
onPropChange("gamemode", gamemodeBox.items[new as Int])
|
||||
}
|
||||
}
|
||||
worldTypeBox.items = FXCollections.observableArrayList(
|
||||
"Normal",
|
||||
|
@ -155,7 +177,59 @@ class PrimaryController {
|
|||
)
|
||||
worldTypeBox.value = "Normal"
|
||||
worldTypeBox.selectionModel.selectedIndexProperty().addListener { _, _, new ->
|
||||
onChoiceBoxChange("world-type", worldTypeBox.items[new as Int])
|
||||
if (!loading) {
|
||||
onPropChange("level-type", worldTypeBox.items[new as Int])
|
||||
}
|
||||
}
|
||||
maxPlayerSpinner.editor.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("max-players", new)
|
||||
}
|
||||
}
|
||||
maxSizeSpinner.editor.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("max-world-size", new)
|
||||
}
|
||||
}
|
||||
portSpinner.editor.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("server-port", new)
|
||||
}
|
||||
}
|
||||
renderSpinner.editor.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("view-distance", new)
|
||||
}
|
||||
}
|
||||
memorySpinner.editor.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("jvm-ram", new)
|
||||
}
|
||||
}
|
||||
spawnSpinner.editor.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("spawn-protection", new)
|
||||
}
|
||||
}
|
||||
simulationSpinner.editor.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("simulation-distance", new)
|
||||
}
|
||||
}
|
||||
maxTickSpinner.editor.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("max-tick-time", new)
|
||||
}
|
||||
}
|
||||
worldNameField.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("level-name", new)
|
||||
}
|
||||
}
|
||||
seedField.textProperty().addListener { _, _, new ->
|
||||
if (!loading) {
|
||||
onPropChange("level-seed", new)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,6 +248,8 @@ class PrimaryController {
|
|||
worldSettingsPane.isDisable = false
|
||||
buildButton.isDisable = false
|
||||
defaultsButton.isDisable = false
|
||||
applyProps()
|
||||
server.dir = result.absolutePath
|
||||
} else {
|
||||
currentDirectoryLabel.text = "<NONE>"
|
||||
parentPane.isDisable = true
|
||||
|
@ -185,33 +261,114 @@ class PrimaryController {
|
|||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private fun onWorldNameChange() {
|
||||
private fun parseBool(bool: String): Boolean {
|
||||
if (bool == "true") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun applyProps() {
|
||||
loading = true
|
||||
flightCheckbox.isSelected = parseBool(server.getProp("allow-flight"))
|
||||
netherCheckbox.isSelected = parseBool(server.getProp("allow-nether"))
|
||||
structuresCheckbox.isSelected = parseBool(server.getProp("generate-structures"))
|
||||
pvpCheckbox.isSelected = parseBool(server.getProp("pvp"))
|
||||
whitelistCheckbox.isSelected = parseBool(server.getProp("white-list"))
|
||||
cmdBlocksCheckbox.isSelected = parseBool(server.getProp("enable-command-block"))
|
||||
playerCountCheckbox.isSelected = parseBool(server.getProp("hide-online-players"))
|
||||
maxPlayerSpinner.valueFactory.value = server.getProp("max-players").toIntOrNull()
|
||||
maxSizeSpinner.valueFactory.value = server.getProp("max-world-size").toIntOrNull()
|
||||
portSpinner.valueFactory.value = server.getProp("server-port").toIntOrNull()
|
||||
renderSpinner.valueFactory.value = server.getProp("view-distance").toIntOrNull()
|
||||
memorySpinner.valueFactory.value = server.getProp("jvm-ram").toIntOrNull()
|
||||
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() }
|
||||
}
|
||||
gamemodeBox.value = server.getProp("gamemode").replaceFirstChar { it.uppercase() }
|
||||
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
|
||||
}
|
||||
|
||||
@FXML
|
||||
private fun onSeedChange() {
|
||||
private fun onCheckboxClick(e: ActionEvent) {
|
||||
val box = e.target as CheckBox
|
||||
when {
|
||||
box == whitelistCheckbox -> {
|
||||
server.setProp("white-list", whitelistCheckbox.isSelected)
|
||||
}
|
||||
box == pvpCheckbox -> {
|
||||
server.setProp("pvp", pvpCheckbox.isSelected)
|
||||
}
|
||||
box == netherCheckbox -> {
|
||||
server.setProp("allow-nether", netherCheckbox.isSelected)
|
||||
}
|
||||
box == cmdBlocksCheckbox -> {
|
||||
server.setProp("enable-command-block", cmdBlocksCheckbox.isSelected)
|
||||
}
|
||||
box == flightCheckbox -> {
|
||||
server.setProp("allow-flight", flightCheckbox.isSelected)
|
||||
}
|
||||
box == structuresCheckbox -> {
|
||||
server.setProp("generate-structures", structuresCheckbox.isSelected)
|
||||
}
|
||||
box == playerCountCheckbox -> {
|
||||
server.setProp("hide-online-players", playerCountCheckbox.isSelected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onPropChange(prop: String, value: String) {
|
||||
when {
|
||||
prop == "gamemode" -> {
|
||||
server.setProp(prop, value.lowercase())
|
||||
}
|
||||
prop == "difficulty" -> {
|
||||
if (value == "Hardcore") {
|
||||
server.setProp("hardcode", "true")
|
||||
server.setProp(prop, "hard")
|
||||
} else {
|
||||
server.setProp("hardcode", "false")
|
||||
server.setProp(prop, value.lowercase())
|
||||
}
|
||||
}
|
||||
prop == "level-type" -> {
|
||||
server.setProp(prop, "minecraft:" + value.lowercase().replace(" ", "_"))
|
||||
}
|
||||
else -> {
|
||||
server.setProp(prop, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private fun onPortChange() {
|
||||
|
||||
private fun onToggleConsole() {
|
||||
if (showingConsole) {
|
||||
primary.getScene().window.height = 743.0
|
||||
dropDownIcon.image = Image(App().javaClass.getResourceAsStream("icons/arrow_down.png"))
|
||||
} else {
|
||||
primary.getScene().window.height = 905.0
|
||||
dropDownIcon.image = Image(App().javaClass.getResourceAsStream("icons/arrow_up.png"))
|
||||
}
|
||||
showingConsole = !showingConsole
|
||||
}
|
||||
|
||||
@FXML
|
||||
private fun onCheckboxClick() {
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private fun onSpinnerChange() {
|
||||
|
||||
}
|
||||
|
||||
private fun onChoiceBoxChange(box: String, selection: String) {
|
||||
|
||||
private fun onDefaults() {
|
||||
val res = createDialog("info", "Reset settings to defaults?\nThere is NO GOING BACK!")
|
||||
if (res) {
|
||||
server.loadProps()
|
||||
applyProps()
|
||||
statusBar.text = "Resetting settings to defaults successful."
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
|
@ -280,19 +437,21 @@ class PrimaryController {
|
|||
withContext(Dispatchers.JavaFx){
|
||||
statusBar.text = "Downloading ${it.key}..."
|
||||
progressBar.progress = ProgressBar.INDETERMINATE_PROGRESS
|
||||
log("Downloading ${it.key} from ${it.value}")
|
||||
}
|
||||
val download = Download(URL(it.value), destinations[it.key]!!)
|
||||
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("")
|
||||
withContext(Dispatchers.JavaFx) {log("Progress: ${prog * 100}%")}
|
||||
if (prog >= 0.01) {
|
||||
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}")}
|
||||
}
|
||||
|
||||
// extract java archive
|
||||
|
@ -300,6 +459,7 @@ class PrimaryController {
|
|||
withContext(Dispatchers.JavaFx) {
|
||||
progressBar.progress = ProgressBar.INDETERMINATE_PROGRESS
|
||||
statusBar.text = "Extracting Java archive..."
|
||||
log("Extracting Java archive to ${directory + "ServerCraft" + File.separator + "Java"}")
|
||||
}
|
||||
var stream = archiver.stream(File(directory + "ServerCraft" + File.separator + "Java" + File.separator + javaFile))
|
||||
val dest = File(directory + "ServerCraft" + File.separator + "Java")
|
||||
|
@ -311,7 +471,10 @@ class PrimaryController {
|
|||
var entry = stream.getNextEntry()
|
||||
var currentEntry = 0.0
|
||||
do {
|
||||
withContext(Dispatchers.JavaFx) {progressBar.progress = currentEntry/entries}
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
progressBar.progress = currentEntry/entries
|
||||
log(entry.name)
|
||||
}
|
||||
entry.extract(dest)
|
||||
entry = stream.getNextEntry()
|
||||
currentEntry++
|
||||
|
@ -335,7 +498,7 @@ class PrimaryController {
|
|||
if (!building) {
|
||||
proc.destroy()
|
||||
}
|
||||
println(line)
|
||||
withContext(Dispatchers.JavaFx) {log(line)}
|
||||
line = br.readLine()
|
||||
currentline++
|
||||
if (currentline > 15) {
|
||||
|
@ -343,7 +506,7 @@ class PrimaryController {
|
|||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
println("Stream closed")
|
||||
withContext(Dispatchers.JavaFx) {log("Stream Closed")}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,7 +533,7 @@ class PrimaryController {
|
|||
@FXML
|
||||
private fun onStart() {
|
||||
if (started) {
|
||||
createDialog("warning", "You should only kill the server if\nabsolutely necessary. Data loss may occur.\nContinue anyway?", "Yes", "No", false)
|
||||
createDialog("warning", "You should only kill the server if\nabsolutely necessary. Data loss may occur.\nContinue anyway?", hold=false)
|
||||
return;
|
||||
}
|
||||
if (!File(directory + "eula.txt").exists()) {
|
||||
|
@ -391,7 +554,7 @@ class PrimaryController {
|
|||
startButton.text = "Kill Server"
|
||||
@Suppress("OPT_IN_USAGE")
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
val builder = ProcessBuilder("java", "-jar", "${server.jar}")
|
||||
val builder = ProcessBuilder("java", "-Xmx${server.getProp("jvm-ram")}M", "-jar", "${server.jar}")
|
||||
builder.directory(File(directory))
|
||||
val proc = builder.start()
|
||||
val reader = InputStreamReader(proc.inputStream)
|
||||
|
@ -406,11 +569,11 @@ class PrimaryController {
|
|||
}
|
||||
proc.destroy()
|
||||
}
|
||||
println(line);
|
||||
withContext(Dispatchers.JavaFx) {log(line)}
|
||||
line = br.readLine()
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
println("Stream closed")
|
||||
withContext(Dispatchers.JavaFx) {log("Stream Closed")}
|
||||
}
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
statusBar.text = if (asyncResult) {
|
||||
|
@ -459,18 +622,18 @@ class PrimaryController {
|
|||
buttonBar.layoutY = 107.0
|
||||
buttonBar.prefWidth = 400.0
|
||||
val noButton = Button("I Disagree")
|
||||
noButton.onMouseClicked = EventHandler<MouseEvent>() {
|
||||
noButton.onAction = EventHandler<ActionEvent>() {
|
||||
result = false
|
||||
dialog.hide()
|
||||
}
|
||||
noButton.isDefaultButton = true
|
||||
val yesButton = Button("I Agree")
|
||||
yesButton.onMouseClicked = EventHandler<MouseEvent>() {
|
||||
yesButton.onAction = EventHandler<ActionEvent>() {
|
||||
result = true
|
||||
dialog.hide()
|
||||
}
|
||||
val eula = Button("View EULA")
|
||||
eula.onMouseClicked = EventHandler<MouseEvent>() {
|
||||
eula.onAction = EventHandler<ActionEvent>() {
|
||||
val desktop = Desktop.getDesktop()
|
||||
if (desktop.isSupported(Desktop.Action.BROWSE)) {
|
||||
// most likely running on Windows or macOS
|
||||
|
@ -500,7 +663,7 @@ class PrimaryController {
|
|||
return result
|
||||
}
|
||||
|
||||
private fun createDialog(type: String, msg: String, yes: String, no: String, hold: Boolean): Boolean {
|
||||
private fun createDialog(type: String, msg: String, yes: String = "Yes", no: String = "No", hold: Boolean = true): Boolean {
|
||||
var result = false
|
||||
val resources = App().javaClass.getResource("icons/$type.png")
|
||||
val dialog = Stage()
|
||||
|
@ -527,7 +690,7 @@ class PrimaryController {
|
|||
buttonBar.layoutY = 107.0
|
||||
buttonBar.prefWidth = 400.0
|
||||
val noButton = Button(no)
|
||||
noButton.onMouseClicked = EventHandler<MouseEvent>() {
|
||||
noButton.onAction = EventHandler<ActionEvent>() {
|
||||
if (hold) {
|
||||
result = false
|
||||
} else {
|
||||
|
@ -536,7 +699,7 @@ class PrimaryController {
|
|||
dialog.hide()
|
||||
}
|
||||
val yesButton = Button(yes)
|
||||
yesButton.onMouseClicked = EventHandler<MouseEvent>() {
|
||||
yesButton.onAction = EventHandler<ActionEvent>() {
|
||||
if (hold) {
|
||||
result = true
|
||||
} else {
|
||||
|
@ -559,10 +722,12 @@ class PrimaryController {
|
|||
|
||||
private fun loadServerDir(dir: String): Boolean {
|
||||
directory = dir
|
||||
// exit if doesn't exist for whatever reason
|
||||
if (!File(directory).isDirectory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add system dir separator for cleaner code
|
||||
if (directory[directory.length-1] != File.separatorChar)
|
||||
directory += File.separatorChar
|
||||
|
||||
|
@ -570,7 +735,7 @@ class PrimaryController {
|
|||
val hasProperties = File(directory + File.separator + "server.properties").isFile
|
||||
val hasServer = findServerJar()
|
||||
|
||||
if (hasDummy && hasServer) {
|
||||
if (hasDummy && hasServer && hasProperties) {
|
||||
// server complete, just read jproperties
|
||||
statusBar.text = "Server found!"
|
||||
startButton.isDisable = false
|
||||
|
@ -581,24 +746,32 @@ class PrimaryController {
|
|||
statusBar.text = "Server needs to be built before starting."
|
||||
} else if (!hasDummy && hasServer) {
|
||||
// server created externally
|
||||
val result = createDialog("warning", "This server directory was not created by \nServerCraft. Errors may occur; copying\nthe world directories to a new folder may be\nsafer. Proceed anyway?", "Yes", "No", true)
|
||||
val result = createDialog("warning", "This server directory was not created by \nServerCraft. Errors may occur; copying\nthe world directories to a new folder may be\nsafer. Proceed anyway?")
|
||||
statusBar.text = "Ready."
|
||||
if (result) {
|
||||
startButton.isDisable = false
|
||||
}
|
||||
server.loadProps(dir)
|
||||
return result
|
||||
} else {
|
||||
// assume clean directory
|
||||
val result = createDialog("info", "There is no server in this directory.\nCreate one?", "Yes", "No", true)
|
||||
val result = createDialog("info", "There is no server in this directory.\nCreate one?")
|
||||
if (result) {
|
||||
File(directory + "ServerCraft").mkdir()
|
||||
startButton.isDisable = true
|
||||
buildButton.text = "Build Server"
|
||||
}
|
||||
statusBar.text = "Ready."
|
||||
server.loadProps()
|
||||
return result
|
||||
}
|
||||
|
||||
if (hasProperties) {
|
||||
server.loadProps(dir)
|
||||
} else {
|
||||
server.loadProps()
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package xyz.brysonsteck.ServerCraft.server
|
|||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
||||
class Download: Runnable {
|
||||
public enum class Status {
|
||||
|
@ -43,7 +44,7 @@ class Download: Runnable {
|
|||
|
||||
try {
|
||||
// Open connection to URL.
|
||||
var connection = url.openConnection() as HttpURLConnection;
|
||||
var connection = url.openConnection() as HttpsURLConnection;
|
||||
|
||||
// Specify what portion of file to download.
|
||||
connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
|
||||
|
@ -53,12 +54,14 @@ class Download: Runnable {
|
|||
|
||||
// Make sure response code is in the 200 range.
|
||||
if (connection.responseCode / 100 != 2) {
|
||||
println(connection.responseCode)
|
||||
status = Status.ERROR
|
||||
}
|
||||
|
||||
// Check for valid content length.
|
||||
contentLength = connection.getContentLength();
|
||||
if (contentLength < 1) {
|
||||
println(connection.getContentLength())
|
||||
status = Status.ERROR
|
||||
}
|
||||
|
||||
|
@ -99,6 +102,7 @@ class Download: Runnable {
|
|||
status = Status.COMPLETE;
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
status = Status.ERROR
|
||||
} finally {
|
||||
// Close file.
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package xyz.brysonsteck.ServerCraft.server
|
||||
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.util.Properties
|
||||
|
||||
public class Server {
|
||||
public var jar = ""
|
||||
public var dir = ""
|
||||
|
||||
private val props = Properties()
|
||||
|
||||
constructor() {
|
||||
public fun loadProps() {
|
||||
props.setProperty("allow-flight", false.toString())
|
||||
props.setProperty("allow-nether", true.toString())
|
||||
props.setProperty("generate-structures", true.toString())
|
||||
|
@ -32,4 +34,24 @@ public class Server {
|
|||
props.setProperty("level-type", "minecraft:normal")
|
||||
props.setProperty("motd", "A server for a dummy")
|
||||
}
|
||||
|
||||
public fun loadProps(dir: String) {
|
||||
val ins = File(dir + File.separator + "server.properties").inputStream()
|
||||
props.load(ins)
|
||||
}
|
||||
|
||||
private fun writeProps() {
|
||||
val outs = File(dir + File.separator + "server.properties").outputStream()
|
||||
props.store(outs, "Minecraft server properties\nCreated with ServerCraft: https://codeberg.org/brysonsteck/ServerCraft")
|
||||
}
|
||||
|
||||
public fun getProp(prop: String): String {
|
||||
return props.getProperty(prop)
|
||||
}
|
||||
|
||||
public fun setProp(key: String, value: Any) {
|
||||
props.setProperty(key, value.toString())
|
||||
writeProps()
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 846 B |
Binary file not shown.
After Width: | Height: | Size: 841 B |
|
@ -9,22 +9,25 @@
|
|||
<?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.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<Pane fx:id="primary" maxHeight="713.0" maxWidth="963.0" minHeight="713.0" minWidth="963.0" prefHeight="713.0" prefWidth="963.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.brysonsteck.ServerCraft.controllers.PrimaryController">
|
||||
<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">
|
||||
<children>
|
||||
<HBox fx:id="directoryPane" prefHeight="39.0" prefWidth="963.0">
|
||||
<children>
|
||||
<Button id="openFile" fx:id="chooseDirectoryButton" lineSpacing="10.0" mnemonicParsing="false" onMouseClicked="#onDirectoryButtonClick" text="Choose Directory...">
|
||||
<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>
|
||||
|
@ -68,7 +71,7 @@
|
|||
<Insets bottom="5.0" left="5.0" right="5.0" top="6.0" />
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<TextField fx:id="worldNameField" onInputMethodTextChanged="#onWorldNameChange" text="world">
|
||||
<TextField fx:id="worldNameField" text="world">
|
||||
<HBox.margin>
|
||||
<Insets top="2.0" />
|
||||
</HBox.margin>
|
||||
|
@ -86,7 +89,7 @@
|
|||
<Insets bottom="5.0" left="5.0" right="5.0" top="6.0" />
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<TextField fx:id="seedField" onInputMethodTextChanged="#onSeedChange" promptText="Leave empty for random seed" HBox.hgrow="ALWAYS">
|
||||
<TextField fx:id="seedField" promptText="Leave empty for random seed" HBox.hgrow="ALWAYS">
|
||||
<HBox.margin>
|
||||
<Insets top="2.0" />
|
||||
</HBox.margin>
|
||||
|
@ -104,7 +107,7 @@
|
|||
<Insets bottom="5.0" left="5.0" right="5.0" top="6.0" />
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<Spinner fx:id="portSpinner" editable="true" onInputMethodTextChanged="#onPortChange" prefWidth="95.0">
|
||||
<Spinner fx:id="portSpinner" editable="true" prefWidth="95.0">
|
||||
<HBox.margin>
|
||||
<Insets top="2.0" />
|
||||
</HBox.margin>
|
||||
|
@ -123,11 +126,11 @@
|
|||
<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" selected="true" text="Allow The Nether" />
|
||||
<CheckBox fx:id="structuresCheckbox" alignment="TOP_LEFT" layoutX="14.0" layoutY="70.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" selected="true" text="Generate Structures (such as villages and strongholds)" />
|
||||
<CheckBox fx:id="pvpCheckbox" layoutX="14.0" layoutY="109.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" selected="true" text="Allow PvP" />
|
||||
<CheckBox fx:id="whitelistCheckbox" alignment="TOP_LEFT" layoutX="14.0" layoutY="138.0" mnemonicParsing="false" onMouseClicked="#onCheckboxClick" text="Enable Whitelist (Only users you specify can join)" />
|
||||
<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">
|
||||
|
@ -173,8 +176,8 @@
|
|||
<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" />
|
||||
<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">
|
||||
|
@ -327,36 +330,57 @@
|
|||
</Pane>
|
||||
<ButtonBar fx:id="buttonBar" buttonOrder="L+R" layoutY="635.0" prefHeight="40.0" prefWidth="963.0">
|
||||
<buttons>
|
||||
<Button fx:id="infoButton" mnemonicParsing="false" onMouseClicked="#onInfo" text="About ServerCraft" ButtonBar.buttonData="LEFT" />
|
||||
<Button fx:id="defaultsButton" disable="true" mnemonicParsing="false" onMouseClicked="#onBuild" text="Reset to Defaults" ButtonBar.buttonData="LEFT" />
|
||||
<Button fx:id="buildButton" disable="true" mnemonicParsing="false" onMouseClicked="#onBuild" text="Build Server" ButtonBar.buttonData="RIGHT" />
|
||||
<Button fx:id="startButton" defaultButton="true" disable="true" mnemonicParsing="false" onMouseClicked="#onStart" prefWidth="120.0" text="Start Server" ButtonBar.buttonData="RIGHT" />
|
||||
<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>
|
||||
<HBox layoutY="680.0" prefHeight="33.0" prefWidth="963.0" style="-fx-background-color: ddd;">
|
||||
<Pane layoutY="680.0" prefHeight="196.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" visible="false">
|
||||
<HBox.margin>
|
||||
<Insets left="10.0" />
|
||||
</HBox.margin>
|
||||
</ProgressBar>
|
||||
<HBox prefWidth="963.0">
|
||||
<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" 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">
|
||||
<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">
|
||||
<font>
|
||||
<Font name="Monospaced Regular" size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</content>
|
||||
</ScrollPane>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="9.0" left="9.0" right="9.0" top="9.0" />
|
||||
</padding>
|
||||
</HBox>
|
||||
</Pane>
|
||||
</children>
|
||||
</Pane>
|
||||
|
|
Loading…
Add table
Reference in a new issue