diff --git a/src/main/java/de/bixilon/minosoft/assets/util/FileAssetsTypes.kt b/src/main/java/de/bixilon/minosoft/assets/util/FileAssetsTypes.kt
new file mode 100644
index 000000000..1662025ae
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/assets/util/FileAssetsTypes.kt
@@ -0,0 +1,21 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.assets.util
+
+object FileAssetsTypes {
+ const val GAME = "game"
+ const val SKINS = "skins"
+ const val SOUNDS = "sounds"
+ const val PIXLYZER = "pixlyzer"
+}
diff --git a/src/main/java/de/bixilon/minosoft/assets/util/FileAssetsUtil.kt b/src/main/java/de/bixilon/minosoft/assets/util/FileAssetsUtil.kt
index 88c1c66cc..4280aa40e 100644
--- a/src/main/java/de/bixilon/minosoft/assets/util/FileAssetsUtil.kt
+++ b/src/main/java/de/bixilon/minosoft/assets/util/FileAssetsUtil.kt
@@ -29,20 +29,20 @@ import de.bixilon.minosoft.util.KUtil
import java.io.*
import java.net.URL
import java.nio.file.Files
+import java.nio.file.Path
import java.security.MessageDigest
object FileAssetsUtil {
- private val EMPTY_BYTE_ARRAY = ByteArray(0)
- private val BASE_PATH = RunConfiguration.HOME_DIRECTORY + "assets/objects/"
+ var BASE_PATH = RunConfiguration.HOME_DIRECTORY.resolve("assets/")
- fun getPath(hash: String): String {
+ fun getPath(type: String, hash: String): Path {
if (hash.length <= 10) {
throw IllegalArgumentException("Hash too short: $hash")
}
if (!hash.isHexString) {
throw IllegalArgumentException("String is not a hex string. Invalid data or manipulated?: $hash")
}
- return BASE_PATH + hash.substring(0, 2) + "/" + hash
+ return BASE_PATH.resolve(type).resolve(hash.substring(0, 2)).resolve(hash)
}
fun downloadAsset(url: String, compress: Boolean = true, hashType: HashTypes = HashTypes.SHA256): String {
diff --git a/src/main/java/de/bixilon/minosoft/config/profile/GlobalProfileManager.kt b/src/main/java/de/bixilon/minosoft/config/profile/GlobalProfileManager.kt
index dedd54b82..6e31cf595 100644
--- a/src/main/java/de/bixilon/minosoft/config/profile/GlobalProfileManager.kt
+++ b/src/main/java/de/bixilon/minosoft/config/profile/GlobalProfileManager.kt
@@ -13,7 +13,6 @@
package de.bixilon.minosoft.config.profile
-import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.type.MapType
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.collections.CollectionUtil.lockMapOf
@@ -41,13 +40,12 @@ import de.bixilon.minosoft.data.registries.identified.ResourceLocation
import de.bixilon.minosoft.gui.eros.crash.ErosCrashReport.Companion.crash
import de.bixilon.minosoft.terminal.RunConfiguration
import de.bixilon.minosoft.util.json.Jackson
-import de.bixilon.minosoft.util.json.ResourceLocationSerializer
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
-import java.io.File
object GlobalProfileManager {
+ private val SELECTED_PROFILES_PATH = RunConfiguration.CONFIG_DIRECTORY.resolve("selected_profiles.json").toFile()
val DEFAULT_MANAGERS: Map>
private val SELECTED_PROFILES_TYPE: MapType = Jackson.MAPPER.typeFactory.constructMapType(HashMap::class.java, ResourceLocation::class.java, String::class.java)
val CLASS_MAPPING: Map, ProfileManager<*>>
@@ -87,13 +85,12 @@ object GlobalProfileManager {
private fun loadSelectedProfiles() {
selectedProfiles.lock.lock()
try {
- val file = File(RunConfiguration.HOME_DIRECTORY + "config/selected_profiles.json")
- if (!file.exists()) {
+ if (!SELECTED_PROFILES_PATH.exists()) {
return
}
this.selectedProfiles.unsafe.clear()
- this.selectedProfiles.unsafe.putAll(Jackson.MAPPER.readValue(file.read(), SELECTED_PROFILES_TYPE))
+ this.selectedProfiles.unsafe.putAll(Jackson.MAPPER.readValue(SELECTED_PROFILES_PATH.read(), SELECTED_PROFILES_TYPE))
} finally {
selectedProfiles.lock.unlock()
}
@@ -109,7 +106,7 @@ object GlobalProfileManager {
val data: Map = Jackson.MAPPER.convertValue(selectedProfiles.unsafe, SELECTED_PROFILES_TYPE)
val jsonString = Jackson.MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(data)
- FileUtil.safeSaveToFile(File(RunConfiguration.HOME_DIRECTORY + "config/selected_profiles.json"), jsonString)
+ FileUtil.safeSaveToFile(SELECTED_PROFILES_PATH, jsonString)
selectedProfilesChanges = false
} catch (exception: Exception) {
exception.crash()
diff --git a/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt b/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt
index 742a78588..fe4f913e5 100644
--- a/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt
+++ b/src/main/java/de/bixilon/minosoft/config/profile/ProfileManager.kt
@@ -37,6 +37,7 @@ import org.kordamp.ikonli.fontawesome5.FontAwesomeSolid
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
+import java.nio.file.Path
import java.nio.file.StandardWatchEventKinds
import java.util.concurrent.locks.ReentrantLock
@@ -57,11 +58,11 @@ interface ProfileManager {
val profiles: AbstractMutableBiMap
var selected: T
- val baseDirectory: File
- get() = File(RunConfiguration.HOME_DIRECTORY + "config/" + namespace.namespace + "/")
+ val baseDirectory: Path
+ get() = RunConfiguration.CONFIG_DIRECTORY.resolve(namespace.namespace)
- fun getPath(profileName: String, baseDirectory: File = this.baseDirectory): String {
- return baseDirectory.path + "/" + profileName + "/" + namespace.path + ".json"
+ fun getPath(profileName: String, baseDirectory: Path = this.baseDirectory): Path {
+ return baseDirectory.resolve(profileName).resolve(namespace.path + ".json")
}
/**
diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/crash/ErosCrashReport.kt b/src/main/java/de/bixilon/minosoft/gui/eros/crash/ErosCrashReport.kt
index 344829126..66252befe 100644
--- a/src/main/java/de/bixilon/minosoft/gui/eros/crash/ErosCrashReport.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/eros/crash/ErosCrashReport.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2022 Moritz Zwerger
+ * Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -42,7 +42,6 @@ import javafx.scene.text.TextFlow
import javafx.stage.Modality
import javafx.stage.Stage
import javafx.stage.Window
-import java.io.File
import java.io.FileOutputStream
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat
@@ -118,7 +117,7 @@ class ErosCrashReport : JavaFXWindowController() {
var crashReportPath: String?
try {
- val crashReportFolder = File(RunConfiguration.HOME_DIRECTORY + "crash-reports")
+ val crashReportFolder = RunConfiguration.HOME_DIRECTORY.resolve("crash-reports").toFile()
crashReportFolder.mkdirs()
crashReportPath = "${crashReportFolder.slashPath}/crash-${SimpleDateFormat("yyyy-MM-dd-HH.mm.ss").format(millis())}.txt"
diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt
index dea372866..574d707ce 100644
--- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt
+++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2022 Moritz Zwerger
+ * Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -19,7 +19,6 @@ import de.bixilon.kutil.concurrent.pool.ThreadPool
import de.bixilon.kutil.concurrent.pool.ThreadPoolRunnable
import de.bixilon.kutil.file.FileUtil.createParent
import de.bixilon.kutil.file.FileUtil.slashPath
-import de.bixilon.kutil.time.TimeUtil
import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.data.text.BaseComponent
import de.bixilon.minosoft.data.text.TextComponent
@@ -33,7 +32,6 @@ import de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.confirmation.Delete
import de.bixilon.minosoft.gui.rendering.system.base.PixelTypes
import de.bixilon.minosoft.terminal.RunConfiguration
import java.awt.image.BufferedImage
-import java.io.File
import java.text.SimpleDateFormat
import javax.imageio.ImageIO
@@ -47,11 +45,13 @@ class ScreenshotTaker(
val height = context.window.size.y
val buffer = context.renderSystem.readPixels(Vec2i(0, 0), Vec2i(width, height), PixelTypes.RGBA)
- val basePath = "${RunConfiguration.HOME_DIRECTORY}/screenshots/${context.connection.address.hostname}/${DATE_FORMATTER.format(millis())}"
- var path = "$basePath.png"
+ val path = RunConfiguration.HOME_DIRECTORY.resolve("screenshots").resolve(context.connection.address.hostname)
+
+ val timestamp = DATE_FORMATTER.format(millis())
+ var filename = "$timestamp.png"
var i = 1
- while (File(path).exists()) {
- path = "${basePath}_${i++}.png"
+ while (path.resolve(filename).toFile().exists()) {
+ filename = "${timestamp}_${i++}.png"
if (i > MAX_FILES_CHECK) {
throw StackOverflowError("There are already > $MAX_FILES_CHECK screenshots with this date! Please try again later!")
}
@@ -71,7 +71,7 @@ class ScreenshotTaker(
}
}
- val file = File(path)
+ val file = path.resolve(filename).toFile()
file.createParent()
ImageIO.write(bufferedImage, "png", file)
diff --git a/src/main/java/de/bixilon/minosoft/modding/loader/ModLoader.kt b/src/main/java/de/bixilon/minosoft/modding/loader/ModLoader.kt
index 9cd3776a9..374f3b3fb 100644
--- a/src/main/java/de/bixilon/minosoft/modding/loader/ModLoader.kt
+++ b/src/main/java/de/bixilon/minosoft/modding/loader/ModLoader.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2022 Moritz Zwerger
+ * Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -31,7 +31,7 @@ import kotlin.reflect.jvm.javaField
object ModLoader {
- private val BASE_PATH = RunConfiguration.HOME_DIRECTORY + "mods/"
+ private val BASE_PATH = RunConfiguration.HOME_DIRECTORY.resolve("mods")
private var latch: CountUpAndDownLatch? = null
val mods = ModList()
var currentPhase by observed(LoadingPhases.PRE_BOOT)
@@ -39,7 +39,7 @@ object ModLoader {
var state by observed(PhaseStates.WAITING)
private set
- private val LoadingPhases.path: File get() = File(BASE_PATH + name.lowercase())
+ private val LoadingPhases.path: File get() = BASE_PATH.resolve(name.lowercase()).toFile()
private fun createDirectories() {
val created: MutableList = mutableListOf()
diff --git a/src/main/java/de/bixilon/minosoft/terminal/CommandLineArguments.kt b/src/main/java/de/bixilon/minosoft/terminal/CommandLineArguments.kt
index 5b8183a95..60f3a5711 100644
--- a/src/main/java/de/bixilon/minosoft/terminal/CommandLineArguments.kt
+++ b/src/main/java/de/bixilon/minosoft/terminal/CommandLineArguments.kt
@@ -15,6 +15,7 @@ package de.bixilon.minosoft.terminal
import de.bixilon.kutil.shutdown.AbstractShutdownReason
import de.bixilon.kutil.shutdown.ShutdownManager
+import de.bixilon.minosoft.assets.util.FileAssetsUtil
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
import de.bixilon.minosoft.modding.loader.parameters.ModParameters
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
@@ -26,6 +27,7 @@ import net.sourceforge.argparse4j.impl.Arguments
import net.sourceforge.argparse4j.inf.ArgumentParserException
import net.sourceforge.argparse4j.inf.Namespace
import java.io.PrintWriter
+import java.nio.file.Path
object CommandLineArguments {
lateinit var ARGUMENTS: List
@@ -92,6 +94,14 @@ object CommandLineArguments {
addArgument("--mod_parameters")
.action(Arguments.store())
.help("JSON of custom mod parameters")
+
+ addArgument("--home")
+ .action(Arguments.store())
+ .help("Home path of minosoft")
+
+ addArgument("--assets")
+ .action(Arguments.store())
+ .help("Path where assets are stored")
}
fun parse(args: Array) {
@@ -137,5 +147,10 @@ object CommandLineArguments {
RunConfiguration.IGNORE_YGGDRASIL = namespace.getBoolean("ignore_yggdrasil")
RunConfiguration.IGNORE_MODS = namespace.getBoolean("ignore_mods")
namespace.getString("mod_parameters")?.let { RunConfiguration.MOD_PARAMETERS = Jackson.MAPPER.readValue(it, ModParameters::class.java) }
+
+
+
+ namespace.getString("home")?.let { RunConfiguration.setHome(Path.of(it)) }
+ namespace.getString("assets")?.let { FileAssetsUtil.BASE_PATH = Path.of(it) }
}
}
diff --git a/src/main/java/de/bixilon/minosoft/terminal/RunConfiguration.kt b/src/main/java/de/bixilon/minosoft/terminal/RunConfiguration.kt
index cd90fe470..a297fa1af 100644
--- a/src/main/java/de/bixilon/minosoft/terminal/RunConfiguration.kt
+++ b/src/main/java/de/bixilon/minosoft/terminal/RunConfiguration.kt
@@ -14,13 +14,13 @@
package de.bixilon.minosoft.terminal
import com.google.common.base.StandardSystemProperty
-import de.bixilon.kutil.file.FileUtil.slashPath
+import de.bixilon.kutil.cast.CastUtil.unsafeNull
import de.bixilon.kutil.os.OSTypes
import de.bixilon.kutil.os.PlatformInfo
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
import de.bixilon.minosoft.modding.loader.parameters.ModParameters
-import java.io.File
import java.io.IOException
+import java.nio.file.Path
object RunConfiguration {
var LOG_COLOR_MESSAGE = true // The message (after all prefixes) should be colored with ANSI color codes
@@ -35,27 +35,17 @@ object RunConfiguration {
var AUTO_CONNECT_TO: String? = null
- var HOME_DIRECTORY: String = let {
- // Sets Config.homeDir to the correct folder per OS
- var homeDir: String = System.getProperty(StandardSystemProperty.USER_HOME.key())
- if (!homeDir.endsWith(File.separator)) {
- homeDir += "/"
- }
- homeDir += when (PlatformInfo.OS) {
- OSTypes.LINUX -> ".local/share/minosoft/"
- OSTypes.WINDOWS -> "AppData/Roaming/Minosoft/"
- OSTypes.MAC -> "Library/Application Support/Minosoft/"
- else -> ".minosoft/"
- }
- val folder = File(homeDir)
- if (!folder.exists() && !folder.mkdirs()) {
- // failed creating folder
- throw IOException("Could not create home folder ($homeDir)!")
- }
- folder.slashPath + "/"
+ var HOME_DIRECTORY: Path = unsafeNull()
+ private set
+ var CONFIG_DIRECTORY: Path = unsafeNull()
+ private set
+
+ init {
+ setDefaultHome()
}
- val TEMPORARY_FOLDER = System.getProperty("java.io.tmpdir", "$HOME_DIRECTORY/tmp/") + "/minosoft/"
+
+ val TEMPORARY_FOLDER: Path = Path.of(System.getProperty("java.io.tmpdir") ?: "$HOME_DIRECTORY/tmp/", "/minosoft/")
val X_START_ON_FIRST_THREAD_SET = System.getenv("JAVA_STARTED_ON_FIRST_THREAD_${ProcessHandle.current().pid()}") == "1"
@@ -71,4 +61,41 @@ object RunConfiguration {
var IGNORE_MODS = false
var MOD_PARAMETERS = ModParameters()
+
+
+ private fun setDefaultHome() {
+ val user = System.getProperty(StandardSystemProperty.USER_HOME.key()) ?: throw IllegalStateException("Can not get user home!")
+
+ val home = Path.of(user, when (PlatformInfo.OS) {
+ OSTypes.LINUX -> ".local/share/minosoft/"
+ OSTypes.WINDOWS -> "AppData/Roaming/Minosoft/"
+ OSTypes.MAC -> "Library/Application Support/Minosoft/"
+ else -> ".minosoft/"
+ })
+ setHome(home)
+
+ val config = when (PlatformInfo.OS) {
+ OSTypes.LINUX -> Path.of(user, ".config/minosoft")
+ else -> home
+ }
+ setConfig(config)
+ }
+
+ fun setHome(path: Path) {
+ val folder = path.toFile()
+
+ if (!folder.exists() && !folder.mkdirs()) {
+ throw IOException("Can not create home directory: $path")
+ }
+ HOME_DIRECTORY = path
+ }
+
+ fun setConfig(path: Path) {
+ val folder = path.toFile()
+
+ if (!folder.exists() && !folder.mkdirs()) {
+ throw IOException("Can not create home directory: $path")
+ }
+ CONFIG_DIRECTORY = path
+ }
}
diff --git a/src/main/java/de/bixilon/minosoft/util/crash/section/RuntimeSection.kt b/src/main/java/de/bixilon/minosoft/util/crash/section/RuntimeSection.kt
index 66164b89f..cca4e0bdb 100644
--- a/src/main/java/de/bixilon/minosoft/util/crash/section/RuntimeSection.kt
+++ b/src/main/java/de/bixilon/minosoft/util/crash/section/RuntimeSection.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2022 Moritz Zwerger
+ * Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -23,5 +23,6 @@ class RuntimeSection : CrashSection(
"JVM flags" to ManagementFactory.getRuntimeMXBean().inputArguments,
"Environment" to System.getenv(),
"Home directory" to RunConfiguration.HOME_DIRECTORY,
+ "Config directory" to RunConfiguration.CONFIG_DIRECTORY,
)
)